forge-autonomy 2.7.36__tar.gz → 2.7.37__tar.gz
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.
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/PKG-INFO +1 -1
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/installed_lifecycle.py +13 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/preserved_lifecycle.py +3 -2
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/qualification/server_runtime.py +47 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge_autonomy.egg-info/PKG-INFO +1 -1
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/product-version.json +1 -1
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_installed_lifecycle.py +29 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_preserved_lifecycle.py +42 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/MANIFEST.in +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/README.md +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/__init__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/__main__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/_version.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/action_derivation_canary_closure.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/action_derivation_evidence.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/action_derivation_qualification.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/action_derivation_reattempt.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/ai_architect/__init__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/ai_architect/provider_registry.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/api/installed-health-component-registry-1.0.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/api/operations-read-openapi-v1.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/api/operations-read-postman-v1.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/api/server-openapi-v1.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/api/server-postman-v1.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/architecture/__init__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/architecture/advisor.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/architecture/presentation.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/architecture/workspace.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/autonomous_orchestrator.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/business/__init__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/business/advisor.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/business/ingress.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/business/presentation.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/business/workspace.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/canary.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/capabilities/__init__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/capabilities/delegation.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/completion/__init__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/completion/assessor.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/completion/host_control_observer.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/completion/mission.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/completion/repository_observer.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/constitutional/__init__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/constitutional/assessor.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/core/__init__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/core/json_store.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/decision_evidence/__init__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/decision_evidence/repository.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/dispatcher/__init__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/dispatcher/dispatcher.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/ep_simulator.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/execution/__init__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/execution/loop.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/execution/presentation.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/execution_host_configuration.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/foundation/__init__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/foundation/loader.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/generation_two.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/generation_two_execution.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/governance/__init__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/governance/execution_policy.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/governance/profiles.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/governance_authority.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/installed_health.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/intake.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/integration/__init__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/integration/coordinator.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/integration/repository.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/knowledge/__init__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/knowledge/consumer.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/knowledge/registry.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/lifecycle/__init__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/lifecycle/store.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/mission_amendment.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/mission_cli.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/mission_scheduler.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/__init__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/action.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/action_derivation.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/agent_policy.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/ai_architect_provider.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/ai_architect_session.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/ai_provider_registry.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/architecture_mission.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/architecture_reasoning.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/architecture_review.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/codex_runtime_prompt.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/constitutional_validation.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/criterion_assessment.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/criterion_observation.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/decision_evidence.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/execution_host.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/foundation.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/historical_intent.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/integration.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/intent.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/intent_authoring.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/mission.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/mission_candidate.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/mission_completion.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/mission_planner.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/mission_recommendation.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/phase_completion.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/planning.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/producer.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/prompt_artifact.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/proposal.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/runtime_prompt.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/models/solution_template.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/operations_read_api.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/operator_identity.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/planner/__init__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/planner/action_derivation.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/planner/codex_cli_session.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/planner/durable_derivation.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/planner/engine.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/planner/openai_responses.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/planner/provider_adapter.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/planning/__init__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/planning/loader.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/planning/registry.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/portfolio_intelligence.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/programme_authorization.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/prompts/__init__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/prompts/codex_cli.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/prompts/generator.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/proposals/__init__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/proposals/generator.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/provider_context.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/provider_security.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/qualification/__init__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/qualification/bootstrap_sequence.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/qualification/criterion_completion.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/qualification/generation_one.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/qualification/installed_smoke.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/recommendations/__init__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/recommendations/engine.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/repository_truth.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/review/__init__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/review/engine.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/runtime/__init__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/runtime/bootstrap.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/runtime/data_root.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/runtime/database.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/runtime/dynamic_mission.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/runtime/evidence.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/runtime/execution_context.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/runtime/health.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/runtime/mission_controller.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/runtime/operational_reset.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/runtime/runner.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/runtime/service.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/scheduler/__init__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/scheduler/adapter.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/scheduler/ep_http_adapter.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/scheduler/ep_v12.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/scheduler/scheduler.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/schemas/capability-registry-1.0.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/schemas/capability.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/schemas/common.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/schemas/decision-evidence-1.0.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/schemas/engineering-goal-0.5.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/schemas/engineering-increment-proposal-0.5.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/schemas/engineering-mode.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/schemas/engineering-plan-0.5.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/schemas/engineering-platform-peer-configuration-1.0.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/schemas/engineering-platform-peer-configuration-1.1.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/schemas/engineering-prompt-artifact-0.7.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/schemas/engineering-proposal-0.6.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/schemas/evidence-reference-0.5.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/schemas/foundation-document.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/schemas/governance-profile.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/schemas/knowledge-source-0.4.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/schemas/knowledge-source.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/schemas/mission-candidate-1.0.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/schemas/mission-candidate-1.1.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/schemas/phase-completion-1.0.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/schemas/planning-document-0.5.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/schemas/repository-catalog.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/schemas/repository.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/schemas/solution-template-1.0.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/schemas/workspace.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/secure_store.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/server_runtime.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/solutions/__init__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/solutions/catalogue.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/solutions/generator.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/state/__init__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/state/mission_state.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge/workspace/__init__.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge_autonomy.egg-info/SOURCES.txt +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge_autonomy.egg-info/dependency_links.txt +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge_autonomy.egg-info/entry_points.txt +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/forge_autonomy.egg-info/top_level.txt +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/pyproject.toml +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/schemas/capability-registry-1.0.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/schemas/capability.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/schemas/common.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/schemas/decision-evidence-1.0.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/schemas/engineering-goal-0.5.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/schemas/engineering-increment-proposal-0.5.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/schemas/engineering-mode.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/schemas/engineering-plan-0.5.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/schemas/engineering-prompt-artifact-0.7.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/schemas/engineering-proposal-0.6.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/schemas/evidence-reference-0.5.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/schemas/foundation-document.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/schemas/governance-profile.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/schemas/knowledge-source-0.4.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/schemas/knowledge-source.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/schemas/mission-candidate-1.0.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/schemas/mission-candidate-1.1.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/schemas/phase-completion-1.0.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/schemas/planning-document-0.5.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/schemas/repository-catalog.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/schemas/repository.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/schemas/solution-template-1.0.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/schemas/workspace.schema.json +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/setup.cfg +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_action_derivation.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_action_derivation_canary_closure.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_action_derivation_evidence.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_action_derivation_qualification.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_adaptive_action_sizing_design.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_agent_policy.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_aggregate_health_roadmap.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_ai_architect_provider.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_ai_architect_session.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_ai_development_projection.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_ai_provider_registry.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_architecture_reasoning.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_architecture_review_engine.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_architecture_workspace.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_autonomous_orchestrator.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_bootstrap_adapter.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_bootstrap_mission_canary.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_bootstrap_mission_runner.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_bootstrap_mission_scheduler.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_bootstrap_sequence_qualification.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_business_governance_ingress.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_business_workspace.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_canonical_data_root.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_capability_delegation.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_codex_cli_runtime_prompt.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_codex_cli_session.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_constitutional_validation.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_criterion_assessment_contract.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_criterion_ep_http_boundary.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_criterion_planning_context.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_decision_evidence.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_default_project_quality_policy.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_distribution_identity.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_durable_action_derivation.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_dynamic_mission_capability.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_engineering_action_architecture.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_engineering_intent_authoring.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_engineering_intent_lifecycle.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_engineering_mission.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_engineering_planning.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_engineering_prompt_artifacts.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_engineering_proposals.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_ep_http_adapter.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_ep_simulator.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_ep_simulator_rolling_planning.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_execution_context.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_execution_host_configuration.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_execution_host_contract.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_execution_loop.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_existing_release_reconciliation.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_forge_console_admin_parity_contract.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_forge_console_configuration_contract.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_forge_console_hosting_contract.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_forge_operations_console_roadmap.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_forge_outer_loop_ci_roadmap.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_forge_v1_bootstrap_scheduler_contract.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_forge_v1_implementation_dag.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_foundation_loader.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_foundation_models.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_generation_one_bootstrap_qualification.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_generation_two_execution.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_generation_two_mission_intake.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_governance_authority.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_governed_coverage.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_historical_engineering_intent.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_host_control_completion.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_inner_loop_ci_contract.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_installed_dynamic_mission_runtime.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_installed_forge_update.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_integration_coordination.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_knowledge_consumption.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_live_project_roadmap_contract.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_mission_completion_evaluator.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_mission_controller.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_mission_dispatcher.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_mission_planner.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_mission_recommendation_engine.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_mission_recommendation_lifecycle.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_mission_runtime_projection.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_mission_runtime_scheduler.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_mission_state_store.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_mission_status.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_openai_action_derivation.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_operational_reset.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_operations_health.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_operations_read_api.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_operator_identity.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_phase_completion.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_platform_contract_documents.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_portfolio_intelligence_operation.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_producer_contract.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_product_version_operations.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_production_release_workflow.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_productization_reconciliation.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_programme_authorization.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_provider_context.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_provider_security.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_pypi_distribution_readback.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_recovered_partial_completion.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_release_operation.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_repository_truth.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_role_aware_conversations_contract.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_runtime_bootstrap.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_runtime_database.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_runtime_evidence.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_runtime_health.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_runtime_instance_persistence.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_runtime_prompt_generation.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_runtime_service.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_runtime_status_projection.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_scheduler_dependency_boundary.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_schemas.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_secure_store.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_server_api_contract.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_server_runtime.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_solution_templates.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_substantive_mission_completion.py +0 -0
- {forge_autonomy-2.7.36 → forge_autonomy-2.7.37}/tests/test_terminal_continuation_replay.py +0 -0
|
@@ -498,6 +498,13 @@ def _exclusive_locks(paths: tuple[Path, ...]) -> Iterator[None]:
|
|
|
498
498
|
|
|
499
499
|
|
|
500
500
|
def _assert_tree_has_no_links(root: Path) -> str:
|
|
501
|
+
"""Prove one mutable instance tree is exclusively product-owned and safe."""
|
|
502
|
+
_assert_no_symlink_components(root)
|
|
503
|
+
root_info = root.lstat()
|
|
504
|
+
if not stat.S_ISDIR(root_info.st_mode):
|
|
505
|
+
raise InstalledLifecycleError("instance root is not a directory")
|
|
506
|
+
if stat.S_IMODE(root_info.st_mode) & 0o022:
|
|
507
|
+
raise InstalledLifecycleError("instance root is group/world writable")
|
|
501
508
|
entries: list[dict[str, object]] = []
|
|
502
509
|
for directory, names, files in os.walk(root, topdown=True, followlinks=False):
|
|
503
510
|
parent = Path(directory)
|
|
@@ -508,8 +515,14 @@ def _assert_tree_has_no_links(root: Path) -> str:
|
|
|
508
515
|
raise InstalledLifecycleError(f"instance tree contains an unsafe symbolic link: {path}")
|
|
509
516
|
if not (stat.S_ISDIR(info.st_mode) or stat.S_ISREG(info.st_mode)):
|
|
510
517
|
raise InstalledLifecycleError(f"instance tree contains an unsupported filesystem entry: {path}")
|
|
518
|
+
if stat.S_IMODE(info.st_mode) & 0o022:
|
|
519
|
+
raise InstalledLifecycleError(f"instance tree contains a group/world writable entry: {path}")
|
|
520
|
+
if stat.S_ISREG(info.st_mode) and info.st_nlink != 1:
|
|
521
|
+
raise InstalledLifecycleError(f"instance tree contains a non-exclusive hardlinked file: {path}")
|
|
511
522
|
entries.append({
|
|
512
523
|
"path": str(path.relative_to(root)), "mode": stat.S_IFMT(info.st_mode),
|
|
524
|
+
"permissions": stat.S_IMODE(info.st_mode),
|
|
525
|
+
"links": info.st_nlink if stat.S_ISREG(info.st_mode) else None,
|
|
513
526
|
"size": info.st_size if stat.S_ISREG(info.st_mode) else None,
|
|
514
527
|
})
|
|
515
528
|
return _digest_bytes(_json_bytes(entries))
|
|
@@ -22,6 +22,7 @@ from .installed_lifecycle import (
|
|
|
22
22
|
_assert_identity,
|
|
23
23
|
_assert_no_symlink_components,
|
|
24
24
|
_assert_quiescent,
|
|
25
|
+
_assert_tree_has_no_links,
|
|
25
26
|
_atomic_json,
|
|
26
27
|
_digest_bytes,
|
|
27
28
|
_exclusive_locks,
|
|
@@ -41,8 +42,8 @@ PROVIDER_AUTH_PRESERVED = "PRESERVED_REQUIRES_REVERIFICATION"
|
|
|
41
42
|
|
|
42
43
|
|
|
43
44
|
def _content_tree_digest(root: Path) -> str:
|
|
44
|
-
"""Bind every regular byte
|
|
45
|
-
|
|
45
|
+
"""Bind every regular byte after shared exclusive-ownership admission."""
|
|
46
|
+
_assert_tree_has_no_links(root)
|
|
46
47
|
entries: list[dict[str, object]] = []
|
|
47
48
|
for directory, names, files in os.walk(root, topdown=True, followlinks=False):
|
|
48
49
|
parent = Path(directory)
|
|
@@ -22,6 +22,7 @@ from urllib.request import Request, urlopen
|
|
|
22
22
|
from forge._version import canonical_version
|
|
23
23
|
from forge.ep_simulator import EpSimulatorServer, EpSimulatorState
|
|
24
24
|
from forge.installed_lifecycle import (
|
|
25
|
+
InstalledLifecycleError,
|
|
25
26
|
InstalledUninstallDispatcher,
|
|
26
27
|
UninstallRequest,
|
|
27
28
|
UpdateAssessmentRequest,
|
|
@@ -249,6 +250,7 @@ def run(*, candidate_wheel: Path | None = None, source_revision: str | None = No
|
|
|
249
250
|
"preserve": "NOT_REQUESTED",
|
|
250
251
|
"restore": "NOT_REQUESTED",
|
|
251
252
|
"purge": "NOT_REQUESTED",
|
|
253
|
+
"filesystem_security": "NOT_REQUESTED",
|
|
252
254
|
}
|
|
253
255
|
if candidate_wheel is not None:
|
|
254
256
|
if source_revision is None or len(source_revision) != 40:
|
|
@@ -265,6 +267,50 @@ def run(*, candidate_wheel: Path | None = None, source_revision: str | None = No
|
|
|
265
267
|
raise RuntimeError("installed lifecycle update assessment did not bind the exact artifact")
|
|
266
268
|
lifecycle["update_assessment"] = "PASS"
|
|
267
269
|
|
|
270
|
+
def unsafe_lifecycle_request(data_root: Path, operation_id: str) -> InstanceLifecycleRequest:
|
|
271
|
+
database = RuntimeBootstrap(data_root=data_root, forge_version=version).open()
|
|
272
|
+
try:
|
|
273
|
+
runtime_id = database.runtime_identity.runtime_id
|
|
274
|
+
installation_id = database.metadata["installation_id"]
|
|
275
|
+
finally:
|
|
276
|
+
database.close()
|
|
277
|
+
return InstanceLifecycleRequest(
|
|
278
|
+
operation_id=operation_id,
|
|
279
|
+
instance_id=runtime_id,
|
|
280
|
+
runtime_id=runtime_id,
|
|
281
|
+
installation_id=installation_id,
|
|
282
|
+
installed_version=version,
|
|
283
|
+
installed_source=source_revision,
|
|
284
|
+
installed_artifact_digest=wheel_digest,
|
|
285
|
+
data_root=str(data_root),
|
|
286
|
+
instances_root=str(root.resolve()),
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
hardlink_root = root / "unsafe-hardlink-instance"
|
|
290
|
+
hardlink_request = unsafe_lifecycle_request(hardlink_root, "installed-hardlink-negative")
|
|
291
|
+
foreign = root / "foreign-hardlink-source"
|
|
292
|
+
foreign.write_text("foreign", encoding="utf-8")
|
|
293
|
+
(hardlink_root / "unsafe-hardlink").hardlink_to(foreign)
|
|
294
|
+
try:
|
|
295
|
+
InstalledPreserveDispatcher(hardlink_request).run()
|
|
296
|
+
except InstalledLifecycleError as error:
|
|
297
|
+
if "hardlinked" not in str(error):
|
|
298
|
+
raise RuntimeError("installed lifecycle rejected hardlink for an unexpected reason") from error
|
|
299
|
+
else:
|
|
300
|
+
raise RuntimeError("installed lifecycle accepted a foreign hardlink")
|
|
301
|
+
|
|
302
|
+
permissive_root = root / "unsafe-permissive-instance"
|
|
303
|
+
permissive_request = unsafe_lifecycle_request(permissive_root, "installed-permissive-negative")
|
|
304
|
+
permissive_root.chmod(0o777)
|
|
305
|
+
try:
|
|
306
|
+
InstalledPreserveDispatcher(permissive_request).run()
|
|
307
|
+
except InstalledLifecycleError as error:
|
|
308
|
+
if "group/world writable" not in str(error):
|
|
309
|
+
raise RuntimeError("installed lifecycle rejected permissive root for an unexpected reason") from error
|
|
310
|
+
else:
|
|
311
|
+
raise RuntimeError("installed lifecycle accepted a group/world writable root")
|
|
312
|
+
lifecycle["filesystem_security"] = "PASS"
|
|
313
|
+
|
|
268
314
|
preserve_request = InstanceLifecycleRequest(
|
|
269
315
|
operation_id="forge-server-runtime-installed-preserve",
|
|
270
316
|
instance_id=identities[0],
|
|
@@ -399,6 +445,7 @@ def run(*, candidate_wheel: Path | None = None, source_revision: str | None = No
|
|
|
399
445
|
"lifecycle_preserve": lifecycle["preserve"],
|
|
400
446
|
"lifecycle_restore": lifecycle["restore"],
|
|
401
447
|
"lifecycle_purge": lifecycle["purge"],
|
|
448
|
+
"lifecycle_filesystem_security": lifecycle["filesystem_security"],
|
|
402
449
|
}
|
|
403
450
|
|
|
404
451
|
|
|
@@ -251,6 +251,35 @@ class UninstallDispatcherTests(InstalledLifecycleFixture):
|
|
|
251
251
|
InstalledUninstallDispatcher(self.uninstall_request()).run()
|
|
252
252
|
self.assertTrue(self.data_root.exists())
|
|
253
253
|
|
|
254
|
+
def test_hardlinked_file_fails_closed(self) -> None:
|
|
255
|
+
foreign = self.root / "foreign-hardlink-source"
|
|
256
|
+
foreign.write_text("foreign", encoding="utf-8")
|
|
257
|
+
(self.data_root / "unsafe-hardlink").hardlink_to(foreign)
|
|
258
|
+
self.assertEqual((self.data_root / "unsafe-hardlink").stat().st_nlink, 2)
|
|
259
|
+
with self.assertRaisesRegex(InstalledLifecycleError, "hardlinked"):
|
|
260
|
+
InstalledUninstallDispatcher(self.uninstall_request()).run()
|
|
261
|
+
self.assertTrue(self.data_root.exists())
|
|
262
|
+
|
|
263
|
+
def test_group_or_world_writable_tree_fails_closed(self) -> None:
|
|
264
|
+
self.data_root.chmod(0o777)
|
|
265
|
+
with self.assertRaisesRegex(InstalledLifecycleError, "group/world writable"):
|
|
266
|
+
InstalledUninstallDispatcher(self.uninstall_request(operation_id="unsafe-root")).run()
|
|
267
|
+
self.data_root.chmod(0o700)
|
|
268
|
+
|
|
269
|
+
unsafe_directory = self.data_root / "unsafe-directory"
|
|
270
|
+
unsafe_directory.mkdir(mode=0o700)
|
|
271
|
+
unsafe_directory.chmod(0o772)
|
|
272
|
+
with self.assertRaisesRegex(InstalledLifecycleError, "group/world writable"):
|
|
273
|
+
InstalledUninstallDispatcher(self.uninstall_request(operation_id="unsafe-directory")).run()
|
|
274
|
+
unsafe_directory.chmod(0o700)
|
|
275
|
+
|
|
276
|
+
unsafe_file = self.data_root / "unsafe-file"
|
|
277
|
+
unsafe_file.write_text("unsafe", encoding="utf-8")
|
|
278
|
+
unsafe_file.chmod(0o666)
|
|
279
|
+
with self.assertRaisesRegex(InstalledLifecycleError, "group/world writable"):
|
|
280
|
+
InstalledUninstallDispatcher(self.uninstall_request(operation_id="unsafe-file")).run()
|
|
281
|
+
self.assertTrue(self.data_root.exists())
|
|
282
|
+
|
|
254
283
|
@unittest.skipIf(fcntl is None, "POSIX lock qualification")
|
|
255
284
|
def test_live_server_lock_blocks_uninstall(self) -> None:
|
|
256
285
|
lock = (self.data_root / "locks" / "forge-server-runtime.lock").open("a+")
|
|
@@ -96,6 +96,48 @@ class PreservedLifecycleTests(unittest.TestCase):
|
|
|
96
96
|
self.restore_request("restore-0001", "preserve-0001")
|
|
97
97
|
).run()
|
|
98
98
|
|
|
99
|
+
def test_preserve_rejects_hardlinks_and_insecure_modes(self) -> None:
|
|
100
|
+
foreign = self.root / "foreign-hardlink-source"
|
|
101
|
+
foreign.write_text("foreign", encoding="utf-8")
|
|
102
|
+
(self.data_root / "unsafe-hardlink").hardlink_to(foreign)
|
|
103
|
+
with self.assertRaisesRegex(InstalledLifecycleError, "hardlinked"):
|
|
104
|
+
InstalledPreserveDispatcher(self.request("preserve-hardlink")).run()
|
|
105
|
+
(self.data_root / "unsafe-hardlink").unlink()
|
|
106
|
+
|
|
107
|
+
self.data_root.chmod(0o777)
|
|
108
|
+
with self.assertRaisesRegex(InstalledLifecycleError, "group/world writable"):
|
|
109
|
+
InstalledPreserveDispatcher(self.request("preserve-root-mode")).run()
|
|
110
|
+
self.data_root.chmod(0o700)
|
|
111
|
+
|
|
112
|
+
unsafe_directory = self.data_root / "unsafe-directory"
|
|
113
|
+
unsafe_directory.mkdir(mode=0o700)
|
|
114
|
+
unsafe_directory.chmod(0o772)
|
|
115
|
+
with self.assertRaisesRegex(InstalledLifecycleError, "group/world writable"):
|
|
116
|
+
InstalledPreserveDispatcher(self.request("preserve-directory-mode")).run()
|
|
117
|
+
unsafe_directory.chmod(0o700)
|
|
118
|
+
|
|
119
|
+
unsafe_file = self.data_root / "unsafe-file"
|
|
120
|
+
unsafe_file.write_text("unsafe", encoding="utf-8")
|
|
121
|
+
unsafe_file.chmod(0o666)
|
|
122
|
+
with self.assertRaisesRegex(InstalledLifecycleError, "group/world writable"):
|
|
123
|
+
InstalledPreserveDispatcher(self.request("preserve-file-mode")).run()
|
|
124
|
+
|
|
125
|
+
def test_restore_rejects_insecure_mode_drift_after_preserve(self) -> None:
|
|
126
|
+
InstalledPreserveDispatcher(self.request("preserve-mode-drift")).run()
|
|
127
|
+
self.data_root.chmod(0o777)
|
|
128
|
+
with self.assertRaisesRegex(InstalledLifecycleError, "group/world writable"):
|
|
129
|
+
InstalledRestoreDispatcher(
|
|
130
|
+
self.restore_request("restore-mode-drift", "preserve-mode-drift")
|
|
131
|
+
).run()
|
|
132
|
+
|
|
133
|
+
def test_purge_rejects_unsafe_tree_before_destructive_boundary(self) -> None:
|
|
134
|
+
unsafe = self.data_root / "unsafe-file"
|
|
135
|
+
unsafe.write_text("unsafe", encoding="utf-8")
|
|
136
|
+
unsafe.chmod(0o666)
|
|
137
|
+
with self.assertRaisesRegex(InstalledLifecycleError, "group/world writable"):
|
|
138
|
+
InstalledPurgeDispatcher(self.request("purge-unsafe")).run()
|
|
139
|
+
self.assertTrue(self.data_root.exists())
|
|
140
|
+
|
|
99
141
|
def test_restore_rejects_source_or_artifact_identity_drift(self) -> None:
|
|
100
142
|
InstalledPreserveDispatcher(self.request("preserve-0001")).run()
|
|
101
143
|
request = self.restore_request("restore-drift", "preserve-0001")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|