forge-autonomy 2.7.37__tar.gz → 2.7.38__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.37/forge_autonomy.egg-info → forge_autonomy-2.7.38}/PKG-INFO +1 -1
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/installed_lifecycle.py +3 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38/forge_autonomy.egg-info}/PKG-INFO +1 -1
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/product-version.json +1 -1
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_installed_forge_update.py +376 -4
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_installed_lifecycle.py +17 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/MANIFEST.in +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/README.md +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/__init__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/__main__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/_version.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/action_derivation_canary_closure.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/action_derivation_evidence.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/action_derivation_qualification.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/action_derivation_reattempt.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/ai_architect/__init__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/ai_architect/provider_registry.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/api/installed-health-component-registry-1.0.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/api/operations-read-openapi-v1.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/api/operations-read-postman-v1.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/api/server-openapi-v1.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/api/server-postman-v1.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/architecture/__init__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/architecture/advisor.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/architecture/presentation.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/architecture/workspace.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/autonomous_orchestrator.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/business/__init__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/business/advisor.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/business/ingress.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/business/presentation.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/business/workspace.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/canary.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/capabilities/__init__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/capabilities/delegation.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/completion/__init__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/completion/assessor.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/completion/host_control_observer.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/completion/mission.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/completion/repository_observer.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/constitutional/__init__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/constitutional/assessor.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/core/__init__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/core/json_store.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/decision_evidence/__init__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/decision_evidence/repository.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/dispatcher/__init__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/dispatcher/dispatcher.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/ep_simulator.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/execution/__init__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/execution/loop.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/execution/presentation.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/execution_host_configuration.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/foundation/__init__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/foundation/loader.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/generation_two.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/generation_two_execution.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/governance/__init__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/governance/execution_policy.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/governance/profiles.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/governance_authority.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/installed_health.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/intake.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/integration/__init__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/integration/coordinator.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/integration/repository.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/knowledge/__init__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/knowledge/consumer.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/knowledge/registry.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/lifecycle/__init__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/lifecycle/store.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/mission_amendment.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/mission_cli.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/mission_scheduler.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/__init__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/action.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/action_derivation.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/agent_policy.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/ai_architect_provider.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/ai_architect_session.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/ai_provider_registry.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/architecture_mission.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/architecture_reasoning.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/architecture_review.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/codex_runtime_prompt.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/constitutional_validation.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/criterion_assessment.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/criterion_observation.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/decision_evidence.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/execution_host.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/foundation.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/historical_intent.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/integration.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/intent.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/intent_authoring.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/mission.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/mission_candidate.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/mission_completion.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/mission_planner.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/mission_recommendation.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/phase_completion.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/planning.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/producer.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/prompt_artifact.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/proposal.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/runtime_prompt.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/models/solution_template.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/operations_read_api.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/operator_identity.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/planner/__init__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/planner/action_derivation.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/planner/codex_cli_session.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/planner/durable_derivation.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/planner/engine.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/planner/openai_responses.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/planner/provider_adapter.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/planning/__init__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/planning/loader.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/planning/registry.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/portfolio_intelligence.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/preserved_lifecycle.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/programme_authorization.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/prompts/__init__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/prompts/codex_cli.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/prompts/generator.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/proposals/__init__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/proposals/generator.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/provider_context.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/provider_security.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/qualification/__init__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/qualification/bootstrap_sequence.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/qualification/criterion_completion.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/qualification/generation_one.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/qualification/installed_smoke.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/qualification/server_runtime.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/recommendations/__init__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/recommendations/engine.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/repository_truth.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/review/__init__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/review/engine.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/runtime/__init__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/runtime/bootstrap.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/runtime/data_root.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/runtime/database.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/runtime/dynamic_mission.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/runtime/evidence.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/runtime/execution_context.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/runtime/health.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/runtime/mission_controller.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/runtime/operational_reset.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/runtime/runner.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/runtime/service.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/scheduler/__init__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/scheduler/adapter.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/scheduler/ep_http_adapter.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/scheduler/ep_v12.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/scheduler/scheduler.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/schemas/capability-registry-1.0.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/schemas/capability.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/schemas/common.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/schemas/decision-evidence-1.0.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/schemas/engineering-goal-0.5.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/schemas/engineering-increment-proposal-0.5.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/schemas/engineering-mode.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/schemas/engineering-plan-0.5.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/schemas/engineering-platform-peer-configuration-1.0.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/schemas/engineering-platform-peer-configuration-1.1.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/schemas/engineering-prompt-artifact-0.7.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/schemas/engineering-proposal-0.6.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/schemas/evidence-reference-0.5.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/schemas/foundation-document.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/schemas/governance-profile.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/schemas/knowledge-source-0.4.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/schemas/knowledge-source.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/schemas/mission-candidate-1.0.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/schemas/mission-candidate-1.1.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/schemas/phase-completion-1.0.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/schemas/planning-document-0.5.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/schemas/repository-catalog.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/schemas/repository.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/schemas/solution-template-1.0.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/schemas/workspace.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/secure_store.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/server_runtime.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/solutions/__init__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/solutions/catalogue.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/solutions/generator.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/state/__init__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/state/mission_state.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge/workspace/__init__.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge_autonomy.egg-info/SOURCES.txt +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge_autonomy.egg-info/dependency_links.txt +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge_autonomy.egg-info/entry_points.txt +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/forge_autonomy.egg-info/top_level.txt +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/pyproject.toml +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/schemas/capability-registry-1.0.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/schemas/capability.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/schemas/common.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/schemas/decision-evidence-1.0.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/schemas/engineering-goal-0.5.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/schemas/engineering-increment-proposal-0.5.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/schemas/engineering-mode.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/schemas/engineering-plan-0.5.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/schemas/engineering-prompt-artifact-0.7.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/schemas/engineering-proposal-0.6.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/schemas/evidence-reference-0.5.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/schemas/foundation-document.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/schemas/governance-profile.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/schemas/knowledge-source-0.4.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/schemas/knowledge-source.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/schemas/mission-candidate-1.0.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/schemas/mission-candidate-1.1.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/schemas/phase-completion-1.0.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/schemas/planning-document-0.5.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/schemas/repository-catalog.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/schemas/repository.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/schemas/solution-template-1.0.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/schemas/workspace.schema.json +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/setup.cfg +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_action_derivation.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_action_derivation_canary_closure.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_action_derivation_evidence.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_action_derivation_qualification.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_adaptive_action_sizing_design.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_agent_policy.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_aggregate_health_roadmap.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_ai_architect_provider.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_ai_architect_session.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_ai_development_projection.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_ai_provider_registry.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_architecture_reasoning.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_architecture_review_engine.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_architecture_workspace.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_autonomous_orchestrator.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_bootstrap_adapter.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_bootstrap_mission_canary.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_bootstrap_mission_runner.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_bootstrap_mission_scheduler.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_bootstrap_sequence_qualification.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_business_governance_ingress.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_business_workspace.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_canonical_data_root.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_capability_delegation.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_codex_cli_runtime_prompt.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_codex_cli_session.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_constitutional_validation.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_criterion_assessment_contract.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_criterion_ep_http_boundary.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_criterion_planning_context.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_decision_evidence.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_default_project_quality_policy.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_distribution_identity.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_durable_action_derivation.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_dynamic_mission_capability.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_engineering_action_architecture.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_engineering_intent_authoring.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_engineering_intent_lifecycle.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_engineering_mission.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_engineering_planning.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_engineering_prompt_artifacts.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_engineering_proposals.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_ep_http_adapter.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_ep_simulator.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_ep_simulator_rolling_planning.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_execution_context.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_execution_host_configuration.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_execution_host_contract.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_execution_loop.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_existing_release_reconciliation.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_forge_console_admin_parity_contract.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_forge_console_configuration_contract.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_forge_console_hosting_contract.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_forge_operations_console_roadmap.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_forge_outer_loop_ci_roadmap.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_forge_v1_bootstrap_scheduler_contract.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_forge_v1_implementation_dag.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_foundation_loader.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_foundation_models.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_generation_one_bootstrap_qualification.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_generation_two_execution.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_generation_two_mission_intake.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_governance_authority.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_governed_coverage.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_historical_engineering_intent.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_host_control_completion.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_inner_loop_ci_contract.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_installed_dynamic_mission_runtime.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_integration_coordination.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_knowledge_consumption.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_live_project_roadmap_contract.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_mission_completion_evaluator.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_mission_controller.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_mission_dispatcher.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_mission_planner.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_mission_recommendation_engine.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_mission_recommendation_lifecycle.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_mission_runtime_projection.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_mission_runtime_scheduler.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_mission_state_store.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_mission_status.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_openai_action_derivation.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_operational_reset.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_operations_health.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_operations_read_api.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_operator_identity.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_phase_completion.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_platform_contract_documents.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_portfolio_intelligence_operation.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_preserved_lifecycle.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_producer_contract.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_product_version_operations.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_production_release_workflow.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_productization_reconciliation.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_programme_authorization.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_provider_context.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_provider_security.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_pypi_distribution_readback.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_recovered_partial_completion.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_release_operation.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_repository_truth.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_role_aware_conversations_contract.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_runtime_bootstrap.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_runtime_database.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_runtime_evidence.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_runtime_health.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_runtime_instance_persistence.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_runtime_prompt_generation.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_runtime_service.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_runtime_status_projection.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_scheduler_dependency_boundary.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_schemas.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_secure_store.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_server_api_contract.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_server_runtime.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_solution_templates.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_substantive_mission_completion.py +0 -0
- {forge_autonomy-2.7.37 → forge_autonomy-2.7.38}/tests/test_terminal_continuation_replay.py +0 -0
|
@@ -52,6 +52,9 @@ SUPPORTED_TRANSITIONS = {
|
|
|
52
52
|
("2.7.32", "2.7.33"): (39, 39),
|
|
53
53
|
("2.7.33", "2.7.34"): (39, 39),
|
|
54
54
|
("2.7.34", "2.7.35"): (39, 39),
|
|
55
|
+
("2.7.35", "2.7.38"): (39, 39),
|
|
56
|
+
("2.7.36", "2.7.38"): (39, 39),
|
|
57
|
+
("2.7.37", "2.7.38"): (39, 39),
|
|
55
58
|
}
|
|
56
59
|
SAME_SCHEMA_39_TRANSITIONS = frozenset(
|
|
57
60
|
transition for transition, schemas in SUPPORTED_TRANSITIONS.items() if schemas == (39, 39)
|
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import base64
|
|
6
|
+
from contextlib import redirect_stdout
|
|
6
7
|
import importlib.util
|
|
7
8
|
from hashlib import sha256
|
|
9
|
+
from io import StringIO
|
|
8
10
|
import json
|
|
9
11
|
import os
|
|
10
12
|
from pathlib import Path
|
|
@@ -18,6 +20,7 @@ import zipfile
|
|
|
18
20
|
|
|
19
21
|
from forge.runtime import RuntimeBootstrap
|
|
20
22
|
import forge.runtime.database as runtime_database
|
|
23
|
+
from forge.installed_lifecycle import SUPPORTED_TRANSITIONS as PACKAGED_TRANSITIONS
|
|
21
24
|
from forge.runtime.operational_reset import MAINTENANCE_TABLES
|
|
22
25
|
|
|
23
26
|
|
|
@@ -294,7 +297,7 @@ class InstalledForgeUpdateTests(unittest.TestCase):
|
|
|
294
297
|
"github_release": {"draft": False},
|
|
295
298
|
},
|
|
296
299
|
}, sort_keys=True), encoding="utf-8")
|
|
297
|
-
if version in {"2.7.25", "2.7.26", "2.7.27", "2.7.28", "2.7.29", "2.7.30", "2.7.31", "2.7.32", "2.7.33", "2.7.34", "2.7.35"}:
|
|
300
|
+
if version in {"2.7.25", "2.7.26", "2.7.27", "2.7.28", "2.7.29", "2.7.30", "2.7.31", "2.7.32", "2.7.33", "2.7.34", "2.7.35", "2.7.38"}:
|
|
298
301
|
# Captured from the actual installed-composition command used by
|
|
299
302
|
# both workflow stages; only the synthetic wheel binding changes.
|
|
300
303
|
summary = json.loads((Path(__file__).parent / "fixtures" /
|
|
@@ -304,7 +307,7 @@ class InstalledForgeUpdateTests(unittest.TestCase):
|
|
|
304
307
|
document = json.loads(receipt.read_text())
|
|
305
308
|
document["qualification"]["criterion_completion"] = summary
|
|
306
309
|
document["publication_receipt"]["criterion_completion"] = summary
|
|
307
|
-
if version in {"2.7.34", "2.7.35"}:
|
|
310
|
+
if version in {"2.7.34", "2.7.35", "2.7.38"}:
|
|
308
311
|
server_runtime = {
|
|
309
312
|
"qualification": "FORGE_SERVER_RUNTIME_V1_INSTALLED_ARTIFACT",
|
|
310
313
|
"version": version,
|
|
@@ -317,12 +320,19 @@ class InstalledForgeUpdateTests(unittest.TestCase):
|
|
|
317
320
|
"production_ep_contacted": False,
|
|
318
321
|
"production_provider_contacted": False,
|
|
319
322
|
}
|
|
320
|
-
if version
|
|
323
|
+
if version in {"2.7.35", "2.7.38"}:
|
|
321
324
|
server_runtime.update({
|
|
322
325
|
"lifecycle_update_assessment": "PASS",
|
|
323
326
|
"lifecycle_uninstall_dispatcher": "PASS",
|
|
324
327
|
"lifecycle_uninstall_replay": "PASS",
|
|
325
328
|
})
|
|
329
|
+
if version == "2.7.38":
|
|
330
|
+
server_runtime.update({
|
|
331
|
+
"lifecycle_preserve": "PASS",
|
|
332
|
+
"lifecycle_restore": "PASS",
|
|
333
|
+
"lifecycle_purge": "PASS",
|
|
334
|
+
"lifecycle_filesystem_security": "PASS",
|
|
335
|
+
})
|
|
326
336
|
document["qualification"]["server_runtime"] = server_runtime
|
|
327
337
|
document["publication_receipt"]["server_runtime"] = server_runtime
|
|
328
338
|
receipt.write_text(json.dumps(document, sort_keys=True))
|
|
@@ -339,6 +349,364 @@ class InstalledForgeUpdateTests(unittest.TestCase):
|
|
|
339
349
|
})
|
|
340
350
|
return request
|
|
341
351
|
|
|
352
|
+
def test_standalone_transition_registry_matches_packaged_policy(self):
|
|
353
|
+
self.assertEqual(update.SUPPORTED_TRANSITIONS, PACKAGED_TRANSITIONS)
|
|
354
|
+
|
|
355
|
+
def test_2735_2736_and_2737_have_direct_same_schema_paths_to_2738(self):
|
|
356
|
+
for existing in ("2.7.35", "2.7.36", "2.7.37"):
|
|
357
|
+
with self.subTest(existing=existing):
|
|
358
|
+
request = self._normal_release_request("2.7.38", existing)
|
|
359
|
+
request = update.UpdateRequest(**{
|
|
360
|
+
**request.__dict__,
|
|
361
|
+
"installed_source": "d" * 40,
|
|
362
|
+
"installed_artifact_digest": "sha256:" + "e" * 64,
|
|
363
|
+
"assessment_digest": "sha256:" + "f" * 64,
|
|
364
|
+
})
|
|
365
|
+
self.assertEqual(update.transition_schemas(request), (39, 39))
|
|
366
|
+
self.assertEqual(update.validate_qualified_artifact(request)["release_route"], "NORMAL")
|
|
367
|
+
|
|
368
|
+
def _assessment_request_2738(self, existing_version="2.7.35"):
|
|
369
|
+
self._same_schema39_transition(
|
|
370
|
+
existing_version=existing_version,
|
|
371
|
+
target_version="2.7.38",
|
|
372
|
+
)
|
|
373
|
+
self.request = update.UpdateRequest(**{
|
|
374
|
+
**self.request.__dict__,
|
|
375
|
+
"installed_source": "d" * 40,
|
|
376
|
+
"installed_artifact_digest": "sha256:" + "e" * 64,
|
|
377
|
+
})
|
|
378
|
+
return self.request
|
|
379
|
+
|
|
380
|
+
def test_2738_standalone_assessment_is_read_only_and_exactly_bound(self):
|
|
381
|
+
request = self._assessment_request_2738()
|
|
382
|
+
before = {
|
|
383
|
+
path.relative_to(self.data_root).as_posix(): update.file_digest(path)
|
|
384
|
+
for path in self.data_root.rglob("*") if path.is_file()
|
|
385
|
+
}
|
|
386
|
+
result = update.assess_update(request)
|
|
387
|
+
after = {
|
|
388
|
+
path.relative_to(self.data_root).as_posix(): update.file_digest(path)
|
|
389
|
+
for path in self.data_root.rglob("*") if path.is_file()
|
|
390
|
+
}
|
|
391
|
+
self.assertEqual(result["state"], "UPDATE_AVAILABLE")
|
|
392
|
+
self.assertFalse(result["mutating"])
|
|
393
|
+
self.assertEqual(result["operation_id"], request.operation_id)
|
|
394
|
+
self.assertEqual(result["request_digest"], request.assessment_request_digest)
|
|
395
|
+
self.assertEqual(result["selected_installation"]["source_revision"], "d" * 40)
|
|
396
|
+
self.assertEqual(result["candidate"]["version"], "2.7.38")
|
|
397
|
+
self.assertEqual(before, after)
|
|
398
|
+
|
|
399
|
+
def test_2738_stale_assessment_fails_before_operation_or_resolver_effect(self):
|
|
400
|
+
request = self._assessment_request_2738()
|
|
401
|
+
assessment = update.assess_update(request)
|
|
402
|
+
stale = update.UpdateRequest(**{
|
|
403
|
+
**request.__dict__,
|
|
404
|
+
"installed_source": "f" * 40,
|
|
405
|
+
"assessment_digest": assessment["assessment_digest"],
|
|
406
|
+
})
|
|
407
|
+
resolver_before = self.resolver.read_bytes()
|
|
408
|
+
controller = update.InstalledForgeUpdateController(stale, process_reader=lambda: ())
|
|
409
|
+
with self.assertRaisesRegex(update.InstalledForgeUpdateError, "assessment"):
|
|
410
|
+
controller.run()
|
|
411
|
+
self.assertFalse(controller.operation_root.exists())
|
|
412
|
+
self.assertEqual(self.resolver.read_bytes(), resolver_before)
|
|
413
|
+
|
|
414
|
+
def test_2738_assessment_rejects_permissive_and_hardlinked_instance_entries(self):
|
|
415
|
+
request = self._assessment_request_2738()
|
|
416
|
+
unsafe = self.data_root / "unsafe-file"
|
|
417
|
+
unsafe.write_text("unsafe", encoding="utf-8")
|
|
418
|
+
unsafe.chmod(0o666)
|
|
419
|
+
result = update.assess_update(request)
|
|
420
|
+
self.assertEqual(result["state"], "UNKNOWN")
|
|
421
|
+
self.assertIn("group/world-writable", result["evidence"]["error"])
|
|
422
|
+
unsafe.chmod(0o600)
|
|
423
|
+
foreign = self.root / "foreign"
|
|
424
|
+
foreign.write_text("foreign", encoding="utf-8")
|
|
425
|
+
unsafe.unlink()
|
|
426
|
+
unsafe.hardlink_to(foreign)
|
|
427
|
+
result = update.assess_update(request)
|
|
428
|
+
self.assertEqual(result["state"], "UNKNOWN")
|
|
429
|
+
self.assertIn("hardlinked", result["evidence"]["error"])
|
|
430
|
+
|
|
431
|
+
def test_2738_assessment_schema_and_foreign_artifact_controls_fail_closed(self):
|
|
432
|
+
request = self._assessment_request_2738()
|
|
433
|
+
with sqlite3.connect(self.data_root / "forge.db") as connection:
|
|
434
|
+
connection.execute("PRAGMA user_version=38")
|
|
435
|
+
schema = update.assess_update(request)
|
|
436
|
+
self.assertEqual(schema["state"], "INCOMPATIBLE")
|
|
437
|
+
self.assertEqual(schema["reason_codes"], ["RUNTIME_SCHEMA_OUTSIDE_BOUNDED_TRANSITION"])
|
|
438
|
+
changed = update.UpdateRequest(**{
|
|
439
|
+
**request.__dict__,
|
|
440
|
+
"wheel_sha256": "sha256:" + "0" * 64,
|
|
441
|
+
})
|
|
442
|
+
foreign = update.assess_update(changed)
|
|
443
|
+
self.assertEqual(foreign["state"], "UNKNOWN")
|
|
444
|
+
self.assertIn("wheel digest", foreign["evidence"]["error"])
|
|
445
|
+
|
|
446
|
+
def test_2738_run_orchestration_binds_assessment_and_terminal_receipt(self):
|
|
447
|
+
request = self._assessment_request_2738()
|
|
448
|
+
assessment = update.assess_update(request)
|
|
449
|
+
request = update.UpdateRequest(**{
|
|
450
|
+
**request.__dict__, "assessment_digest": assessment["assessment_digest"],
|
|
451
|
+
})
|
|
452
|
+
controller = update.InstalledForgeUpdateController(request, process_reader=lambda: ())
|
|
453
|
+
before = update.database_snapshot(self.data_root / "forge.db")
|
|
454
|
+
|
|
455
|
+
def advance(state, phase, **evidence):
|
|
456
|
+
return {**state, **evidence, "phase": phase}
|
|
457
|
+
|
|
458
|
+
with (
|
|
459
|
+
patch.object(update, "reconcile_terminal_dispatcher_for_update",
|
|
460
|
+
side_effect=lambda _request, snapshot, _database: snapshot),
|
|
461
|
+
patch.object(controller, "_stage", side_effect=lambda state: advance(state, "STAGED")),
|
|
462
|
+
patch.object(controller, "_adopt_resolver",
|
|
463
|
+
side_effect=lambda state: advance(state, "ADOPTED", before=before)),
|
|
464
|
+
patch.object(controller, "_backup", side_effect=lambda state, _before: advance(
|
|
465
|
+
state, "BACKED_UP", backup={"status": "PASS", "path": str(controller.backup_path)},
|
|
466
|
+
)),
|
|
467
|
+
patch.object(controller, "_qualify_copy", side_effect=lambda state, _before: advance(
|
|
468
|
+
state, "MIGRATION_QUALIFIED", migration_qualification={"status": "PASS"},
|
|
469
|
+
)),
|
|
470
|
+
patch.object(controller, "_migrate_live", side_effect=lambda state, _before: (
|
|
471
|
+
advance(state, "MIGRATED", live_migration={"status": "PASS"}), before,
|
|
472
|
+
)),
|
|
473
|
+
patch.object(controller, "_activate", side_effect=lambda state, _after: advance(
|
|
474
|
+
state, "ACTIVATED", installed_readback={
|
|
475
|
+
"preservation": {"status": "PASS"},
|
|
476
|
+
"database_snapshot_digest": before["snapshot_digest"],
|
|
477
|
+
},
|
|
478
|
+
)),
|
|
479
|
+
):
|
|
480
|
+
receipt = controller.run()
|
|
481
|
+
|
|
482
|
+
self.assertEqual(receipt["state"], "COMPLETE")
|
|
483
|
+
self.assertEqual(receipt["assessment_digest"], assessment["assessment_digest"])
|
|
484
|
+
self.assertEqual(receipt["installed_source"], request.installed_source)
|
|
485
|
+
self.assertEqual(receipt["installed_artifact_digest"], request.installed_artifact_digest)
|
|
486
|
+
self.assertEqual(receipt["credential_disposition"], "PRESERVED_UNCHANGED")
|
|
487
|
+
self.assertEqual(update._read_json(controller.receipt_path), receipt)
|
|
488
|
+
self.assertEqual(update._read_json(controller.state_path)["phase"], "COMPLETE")
|
|
489
|
+
|
|
490
|
+
def test_cli_assessment_success_mutation_success_and_error_are_machine_readable(self):
|
|
491
|
+
request = self._assessment_request_2738()
|
|
492
|
+
options = {
|
|
493
|
+
"operation-id": request.operation_id,
|
|
494
|
+
"version": request.version,
|
|
495
|
+
"product-source": request.product_source,
|
|
496
|
+
"wheel": request.wheel,
|
|
497
|
+
"wheel-sha256": request.wheel_sha256,
|
|
498
|
+
"qualification-receipt": request.qualification_receipt,
|
|
499
|
+
"qualification-receipt-sha256": request.qualification_receipt_sha256,
|
|
500
|
+
"controller-source": request.controller_source,
|
|
501
|
+
"controller-sha256": request.controller_sha256,
|
|
502
|
+
"data-root": request.data_root,
|
|
503
|
+
"runtime-root": request.runtime_root,
|
|
504
|
+
"runtime-id": request.runtime_id,
|
|
505
|
+
"installation-id": request.installation_id,
|
|
506
|
+
"peer-configuration-digest": request.peer_configuration_digest,
|
|
507
|
+
"resolver": request.resolver,
|
|
508
|
+
"resolver-sha256": request.resolver_sha256,
|
|
509
|
+
"existing-interpreter": request.existing_interpreter,
|
|
510
|
+
"existing-version": request.existing_version,
|
|
511
|
+
"base-python": request.base_python,
|
|
512
|
+
"installed-source": request.installed_source,
|
|
513
|
+
"installed-artifact-digest": request.installed_artifact_digest,
|
|
514
|
+
}
|
|
515
|
+
argv = [item for key, value in options.items() for item in (f"--{key}", value)]
|
|
516
|
+
assessment = update.assess_update(request)
|
|
517
|
+
output = StringIO()
|
|
518
|
+
with redirect_stdout(output):
|
|
519
|
+
self.assertEqual(update.main([*argv, "--assess-only"]), 0)
|
|
520
|
+
self.assertEqual(json.loads(output.getvalue()), assessment)
|
|
521
|
+
|
|
522
|
+
mutation_argv = [*argv, "--assessment-digest", assessment["assessment_digest"]]
|
|
523
|
+
completed = {"state": "COMPLETE", "operation_id": request.operation_id}
|
|
524
|
+
output = StringIO()
|
|
525
|
+
with (
|
|
526
|
+
patch.object(update.InstalledForgeUpdateController, "run", return_value=completed),
|
|
527
|
+
redirect_stdout(output),
|
|
528
|
+
):
|
|
529
|
+
self.assertEqual(update.main(mutation_argv), 0)
|
|
530
|
+
self.assertEqual(json.loads(output.getvalue()), completed)
|
|
531
|
+
|
|
532
|
+
output = StringIO()
|
|
533
|
+
with (
|
|
534
|
+
patch.object(update.InstalledForgeUpdateController, "run",
|
|
535
|
+
side_effect=update.InstalledForgeUpdateError("blocked")),
|
|
536
|
+
redirect_stdout(output),
|
|
537
|
+
):
|
|
538
|
+
self.assertEqual(update.main([*mutation_argv, "--reconcile-staged-controller"]), 1)
|
|
539
|
+
self.assertEqual(json.loads(output.getvalue()), {"status": "ERROR", "error": "blocked"})
|
|
540
|
+
|
|
541
|
+
def test_controller_input_and_utility_failures_are_fail_closed(self):
|
|
542
|
+
invalid = (
|
|
543
|
+
({"operation_id": "../escape"}, "filesystem-safe"),
|
|
544
|
+
({"wheel_sha256": "bad"}, "wheel digest"),
|
|
545
|
+
({"product_source": "short"}, "source revisions"),
|
|
546
|
+
({"wheel": "relative.whl"}, "absolute"),
|
|
547
|
+
({"version": "2.7.38", "installed_source": "short",
|
|
548
|
+
"installed_artifact_digest": "sha256:" + "e" * 64}, "installed source"),
|
|
549
|
+
({"version": "2.7.38", "installed_source": "d" * 40,
|
|
550
|
+
"installed_artifact_digest": "bad"}, "installed artifact"),
|
|
551
|
+
)
|
|
552
|
+
for changes, message in invalid:
|
|
553
|
+
with self.subTest(changes=changes):
|
|
554
|
+
request = update.UpdateRequest(**{**self.request.__dict__, **changes})
|
|
555
|
+
with self.assertRaisesRegex(update.InstalledForgeUpdateError, message):
|
|
556
|
+
request.validate_structure()
|
|
557
|
+
|
|
558
|
+
with self.assertRaisesRegex(update.InstalledForgeUpdateError, "absolute"):
|
|
559
|
+
update._safe_directory(Path("relative"))
|
|
560
|
+
with self.assertRaisesRegex(update.InstalledForgeUpdateError, "unavailable"):
|
|
561
|
+
update._safe_directory(self.root / "missing")
|
|
562
|
+
with self.assertRaisesRegex(update.InstalledForgeUpdateError, "not a symlink"):
|
|
563
|
+
update._resolved_link(self.resolver)
|
|
564
|
+
with self.assertRaisesRegex(update.InstalledForgeUpdateError, "required regular file"):
|
|
565
|
+
update.file_digest(self.root / "missing.bin")
|
|
566
|
+
with self.assertRaisesRegex(update.InstalledForgeUpdateError, "required regular file"):
|
|
567
|
+
update._read_regular_bytes(self.root)
|
|
568
|
+
|
|
569
|
+
guarded = self.root / "guarded-tree"
|
|
570
|
+
guarded.mkdir()
|
|
571
|
+
(guarded / "link").symlink_to(self.resolver)
|
|
572
|
+
with self.assertRaisesRegex(update.InstalledForgeUpdateError, "symbolic link"):
|
|
573
|
+
update._assert_private_owned_tree(guarded)
|
|
574
|
+
(guarded / "link").unlink()
|
|
575
|
+
os.mkfifo(guarded / "special")
|
|
576
|
+
with self.assertRaisesRegex(update.InstalledForgeUpdateError, "special entry"):
|
|
577
|
+
update._assert_private_owned_tree(guarded)
|
|
578
|
+
|
|
579
|
+
malformed = self.root / "malformed.json"
|
|
580
|
+
malformed.write_text("{", encoding="utf-8")
|
|
581
|
+
with self.assertRaisesRegex(update.InstalledForgeUpdateError, "unreadable"):
|
|
582
|
+
update._read_json(malformed)
|
|
583
|
+
malformed.write_text("[]", encoding="utf-8")
|
|
584
|
+
with self.assertRaisesRegex(update.InstalledForgeUpdateError, "not an object"):
|
|
585
|
+
update._read_json(malformed)
|
|
586
|
+
|
|
587
|
+
failure = update.subprocess.CalledProcessError(
|
|
588
|
+
1, ["tool"], output="bounded stdout", stderr="bounded stderr",
|
|
589
|
+
)
|
|
590
|
+
with patch.object(update.subprocess, "run", side_effect=failure):
|
|
591
|
+
with self.assertRaisesRegex(update.InstalledForgeUpdateError, "bounded stderr"):
|
|
592
|
+
update._run(("tool",), cwd=self.root)
|
|
593
|
+
with patch.object(update, "_run", return_value=SimpleNamespace(stdout="not-json")):
|
|
594
|
+
with self.assertRaisesRegex(update.InstalledForgeUpdateError, "malformed"):
|
|
595
|
+
update.installed_identity(Path(sys.executable), cwd=self.root)
|
|
596
|
+
with patch.object(update, "_run", return_value=SimpleNamespace(stdout="[]")):
|
|
597
|
+
with self.assertRaisesRegex(update.InstalledForgeUpdateError, "malformed"):
|
|
598
|
+
update.installed_identity(Path(sys.executable), cwd=self.root)
|
|
599
|
+
|
|
600
|
+
def test_validated_wheel_installation_is_exact_and_tamper_evident(self):
|
|
601
|
+
wheel_bytes, manifest = update._validated_wheel(self.request)
|
|
602
|
+
slot = self.root / "candidate-slot"
|
|
603
|
+
site_packages = slot / "lib" / "python3.14" / "site-packages"
|
|
604
|
+
site_packages.mkdir(parents=True)
|
|
605
|
+
(slot / "bin").mkdir()
|
|
606
|
+
update._install_validated_wheel(slot, wheel_bytes, manifest)
|
|
607
|
+
evidence = update._verify_candidate_files(slot, manifest)
|
|
608
|
+
self.assertEqual(evidence["installed_file_count"], len(manifest))
|
|
609
|
+
self.assertEqual((slot / "bin" / "forge").stat().st_mode & 0o777, 0o700)
|
|
610
|
+
(site_packages / "forge" / "__init__.py").write_text("tampered", encoding="utf-8")
|
|
611
|
+
with self.assertRaisesRegex(update.InstalledForgeUpdateError, "changed="):
|
|
612
|
+
update._verify_candidate_files(slot, manifest)
|
|
613
|
+
|
|
614
|
+
def test_2738_qualification_copy_is_durable_and_replayable(self):
|
|
615
|
+
request = self._assessment_request_2738()
|
|
616
|
+
controller = update.InstalledForgeUpdateController(
|
|
617
|
+
update.UpdateRequest(**{
|
|
618
|
+
**request.__dict__,
|
|
619
|
+
"assessment_digest": update.assess_update(request)["assessment_digest"],
|
|
620
|
+
}),
|
|
621
|
+
process_reader=lambda: (),
|
|
622
|
+
)
|
|
623
|
+
before = update.database_snapshot(self.data_root / "forge.db")
|
|
624
|
+
update._copy_sqlite_backup(self.data_root / "forge.db", controller.backup_path)
|
|
625
|
+
state = controller._state()
|
|
626
|
+
with patch.object(update, "_candidate_migrate", return_value={
|
|
627
|
+
"initialized": True, "storage_schema": "39", "product_version": "2.7.38",
|
|
628
|
+
}):
|
|
629
|
+
qualified = controller._qualify_copy(state, before)
|
|
630
|
+
replayed = controller._qualify_copy(qualified, before)
|
|
631
|
+
self.assertEqual(qualified["phase"], "MIGRATION_QUALIFIED")
|
|
632
|
+
self.assertEqual(qualified["migration_qualification"]["status"], "PASS")
|
|
633
|
+
self.assertEqual(replayed, qualified)
|
|
634
|
+
|
|
635
|
+
def test_2738_activation_uses_exact_candidate_and_readiness_identity(self):
|
|
636
|
+
request = self._assessment_request_2738()
|
|
637
|
+
request = update.UpdateRequest(**{
|
|
638
|
+
**request.__dict__,
|
|
639
|
+
"assessment_digest": update.assess_update(request)["assessment_digest"],
|
|
640
|
+
})
|
|
641
|
+
controller = update.InstalledForgeUpdateController(request, process_reader=lambda: ())
|
|
642
|
+
candidate = controller.slot / "bin" / "forge"
|
|
643
|
+
candidate.parent.mkdir(parents=True)
|
|
644
|
+
candidate.write_text("candidate", encoding="utf-8")
|
|
645
|
+
python = controller.slot / "bin" / "python"
|
|
646
|
+
python.write_text("python", encoding="utf-8")
|
|
647
|
+
controller.stable_resolver.parent.mkdir(parents=True)
|
|
648
|
+
controller.stable_resolver.symlink_to("../current")
|
|
649
|
+
self.resolver.unlink()
|
|
650
|
+
self.resolver.symlink_to(controller.stable_resolver)
|
|
651
|
+
before = update.database_snapshot(self.data_root / "forge.db")
|
|
652
|
+
state = {"phase": "MIGRATED", "before": before}
|
|
653
|
+
identity = {
|
|
654
|
+
"version": "2.7.38",
|
|
655
|
+
"distribution_version": "2.7.38",
|
|
656
|
+
"sys_executable": str(python),
|
|
657
|
+
"module": str(controller.slot / "forge" / "__init__.py"),
|
|
658
|
+
}
|
|
659
|
+
status = {
|
|
660
|
+
"product_version": "2.7.38",
|
|
661
|
+
"data_root": str(self.data_root),
|
|
662
|
+
"instance_id": self.runtime_id,
|
|
663
|
+
"storage_schema": "39",
|
|
664
|
+
}
|
|
665
|
+
with (
|
|
666
|
+
patch.object(update, "installed_identity", return_value=identity),
|
|
667
|
+
patch.object(update, "_run", side_effect=(
|
|
668
|
+
SimpleNamespace(stdout="2.7.38\n"),
|
|
669
|
+
SimpleNamespace(stdout=json.dumps(status)),
|
|
670
|
+
)),
|
|
671
|
+
patch.object(update, "verify_preservation", return_value={"status": "PASS"}),
|
|
672
|
+
):
|
|
673
|
+
activated = controller._activate(state, before)
|
|
674
|
+
self.assertEqual(activated["phase"], "ACTIVATED")
|
|
675
|
+
self.assertEqual(activated["installed_readback"]["status"], status)
|
|
676
|
+
self.assertEqual(self.resolver.resolve(), candidate.resolve())
|
|
677
|
+
|
|
678
|
+
def test_completed_replay_rechecks_receipt_backup_and_slot_evidence(self):
|
|
679
|
+
request = self._assessment_request_2738()
|
|
680
|
+
request = update.UpdateRequest(**{
|
|
681
|
+
**request.__dict__,
|
|
682
|
+
"assessment_digest": update.assess_update(request)["assessment_digest"],
|
|
683
|
+
})
|
|
684
|
+
controller = update.InstalledForgeUpdateController(request, process_reader=lambda: ())
|
|
685
|
+
update._copy_sqlite_backup(self.data_root / "forge.db", controller.backup_path)
|
|
686
|
+
receipt = {
|
|
687
|
+
"state": "COMPLETE",
|
|
688
|
+
"request_digest": request.digest,
|
|
689
|
+
"backup": {
|
|
690
|
+
"path": str(controller.backup_path),
|
|
691
|
+
"sha256": update.file_digest(controller.backup_path),
|
|
692
|
+
},
|
|
693
|
+
}
|
|
694
|
+
update._atomic_json(controller.receipt_path, receipt)
|
|
695
|
+
state = {
|
|
696
|
+
"phase": "COMPLETE",
|
|
697
|
+
"request_digest": request.digest,
|
|
698
|
+
"receipt_sha256": update.file_digest(controller.receipt_path),
|
|
699
|
+
}
|
|
700
|
+
with patch.object(update, "_qualified_artifact", return_value=(
|
|
701
|
+
{"wheel_manifest_digest": "sha256:" + "a" * 64}, b"", {},
|
|
702
|
+
)):
|
|
703
|
+
with self.assertRaisesRegex(update.InstalledForgeUpdateError, "required regular file"):
|
|
704
|
+
controller._verify_complete(state, receipt)
|
|
705
|
+
|
|
706
|
+
controller.database = self.root / "missing-forge.db"
|
|
707
|
+
with self.assertRaisesRegex(update.InstalledForgeUpdateError, "database is unavailable"):
|
|
708
|
+
controller._restore_database_writable()
|
|
709
|
+
|
|
342
710
|
def test_2725_requires_exact_qualifying_and_published_installed_composition(self):
|
|
343
711
|
request = self._normal_release_request("2.7.25", "2.7.24")
|
|
344
712
|
self.assertEqual(update.validate_qualified_artifact(request)["release_route"], "NORMAL")
|
|
@@ -395,8 +763,12 @@ class InstalledForgeUpdateTests(unittest.TestCase):
|
|
|
395
763
|
wrong_transition = update.UpdateRequest(**{
|
|
396
764
|
**request.__dict__, "existing_version": "2.7.21",
|
|
397
765
|
})
|
|
766
|
+
self.assertEqual(
|
|
767
|
+
update.validate_qualified_artifact(wrong_transition)["release_route"],
|
|
768
|
+
"NORMAL",
|
|
769
|
+
)
|
|
398
770
|
with self.assertRaises(update.InstalledForgeUpdateError):
|
|
399
|
-
|
|
771
|
+
wrong_transition.validate()
|
|
400
772
|
|
|
401
773
|
def test_real_schema37_to_38_migration_preserves_history_and_bindings(self) -> None:
|
|
402
774
|
self._installed_schema37()
|
|
@@ -137,6 +137,23 @@ class UpdateAssessmentTests(InstalledLifecycleFixture):
|
|
|
137
137
|
def test_valid_unsupported_transition_is_incompatible(self) -> None:
|
|
138
138
|
self.assertEqual(self.assessment("3.0.0")["state"], "INCOMPATIBLE")
|
|
139
139
|
|
|
140
|
+
def test_declared_server_baselines_assess_directly_to_2738(self) -> None:
|
|
141
|
+
wheel, digest = _write_wheel(self.root, "2.7.38")
|
|
142
|
+
for installed in ("2.7.35", "2.7.36", "2.7.37"):
|
|
143
|
+
data_root = self.instances_root / installed
|
|
144
|
+
database = RuntimeBootstrap(data_root=data_root, forge_version=installed).open()
|
|
145
|
+
runtime_id = database.runtime_identity.runtime_id
|
|
146
|
+
installation_id = database.metadata["installation_id"]
|
|
147
|
+
database.close()
|
|
148
|
+
result = assess_update(UpdateAssessmentRequest(
|
|
149
|
+
data_root=str(data_root), runtime_id=runtime_id, installation_id=installation_id,
|
|
150
|
+
installed_version=installed, installed_source="a" * 40,
|
|
151
|
+
installed_artifact_digest="sha256:" + "b" * 64,
|
|
152
|
+
candidate_version="2.7.38", candidate_source="c" * 40,
|
|
153
|
+
candidate_wheel=str(wheel), candidate_artifact_digest=digest,
|
|
154
|
+
))
|
|
155
|
+
self.assertEqual(result["state"], "UPDATE_AVAILABLE", installed)
|
|
156
|
+
|
|
140
157
|
def test_identity_or_artifact_uncertainty_fails_closed(self) -> None:
|
|
141
158
|
self.assertEqual(self.assessment(runtime_id="runtime-wrong")["state"], "UNKNOWN")
|
|
142
159
|
result = self.assessment(candidate_artifact_digest="sha256:" + "0" * 64)
|
|
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
|