xrefkit 0.6.1__tar.gz → 0.6.3__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.
- {xrefkit-0.6.1 → xrefkit-0.6.3}/PKG-INFO +37 -1
- {xrefkit-0.6.1 → xrefkit-0.6.3}/README.md +36 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/pyproject.toml +1 -1
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_artifact_selected_family.py +4 -3
- xrefkit-0.6.3/tests/test_azure_connection.py +214 -0
- xrefkit-0.6.3/tests/test_azure_import.py +426 -0
- xrefkit-0.6.3/tests/test_azure_recovery.py +411 -0
- xrefkit-0.6.3/tests/test_azure_update_candidate.py +228 -0
- xrefkit-0.6.3/tests/test_azure_writer.py +352 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_brownfield_csharp_structure_definitions.py +5 -3
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_brownfield_file_editing_protocol.py +1 -1
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_business_intake_conversation_definitions.py +5 -4
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_business_intake_definition.py +12 -7
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_catalog_preparation_definition.py +5 -5
- xrefkit-0.6.3/tests/test_ci_workflow_invariants.py +75 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_code_constraint_definition.py +5 -6
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_constraint_derivation_family_definition.py +5 -6
- xrefkit-0.6.3/tests/test_constraint_derivation_selected_family.py +103 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_contribution_returns.py +142 -3
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_dashboard.py +1 -1
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_database_batch_definition_migration.py +5 -5
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_design_business_intake_selected_family.py +2 -1
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_design_planning_definition_migration.py +5 -7
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_dotnet_definition_candidate.py +6 -4
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_editorial_family_definition.py +5 -5
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_editorial_intake_definition.py +5 -5
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_editorial_selected_family.py +4 -3
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_final_skilldefinition_batch.py +2 -1
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_flow_selected_family.py +4 -4
- xrefkit-0.6.3/tests/test_governance_entry.py +353 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_implementation_flow_definition.py +5 -7
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_knowledge_relations_validator.py +18 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_language_review_definition.py +5 -6
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_mcp_subagent_startup.py +68 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_mcp_subagent_startup_integration.py +8 -3
- xrefkit-0.6.3/tests/test_ontology_assessment_validator.py +115 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_os_family_definition.py +5 -5
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_os_knowledge_family_definition.py +5 -5
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_os_selected_family.py +4 -4
- xrefkit-0.6.3/tests/test_plan_markdown.py +185 -0
- xrefkit-0.6.3/tests/test_plan_observation.py +261 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_qa_report_definition.py +5 -11
- xrefkit-0.6.3/tests/test_reporting_profiles.py +230 -0
- xrefkit-0.6.3/tests/test_reporting_quality.py +273 -0
- xrefkit-0.6.3/tests/test_repository_skill_adoption.py +600 -0
- xrefkit-0.6.3/tests/test_repository_startup_pack.py +49 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_security_definition_migration.py +5 -9
- xrefkit-0.6.3/tests/test_site_release_metadata.py +65 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_skill_definition_mcp.py +111 -4
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_skill_definition_runtime.py +19 -4
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_skill_edits.py +7 -8
- xrefkit-0.6.3/tests/test_skill_release_compatibility.py +313 -0
- xrefkit-0.6.3/tests/test_source_analysis_fragments.py +113 -0
- xrefkit-0.6.3/tests/test_work_management.py +328 -0
- xrefkit-0.6.3/tests/test_work_packages.py +141 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_workflow_family_definition.py +5 -6
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/__init__.py +1 -1
- xrefkit-0.6.3/xrefkit/azure_connection.py +246 -0
- xrefkit-0.6.3/xrefkit/azure_import.py +526 -0
- xrefkit-0.6.3/xrefkit/azure_recovery.py +423 -0
- xrefkit-0.6.3/xrefkit/azure_update_candidate.py +249 -0
- xrefkit-0.6.3/xrefkit/azure_writer.py +529 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/cli.py +9 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/dashboard.py +214 -9
- xrefkit-0.6.3/xrefkit/governance_entry.py +412 -0
- xrefkit-0.6.3/xrefkit/governance_entry_cli.py +103 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/mcp/audit.py +3 -2
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/mcp/catalog.py +160 -31
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/mcp/cli.py +33 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/mcp/contribution_returns.py +34 -0
- xrefkit-0.6.3/xrefkit/mcp/governed_overlays.py +41 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/mcp/knowledge_edits.py +25 -7
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/mcp/schemas.py +2 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/mcp/server.py +52 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/mcp/skill_edits.py +34 -5
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/mcp/subagent_startup.py +8 -1
- xrefkit-0.6.3/xrefkit/mcp/update_gate_intake.py +78 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/packmeta.py +15 -4
- xrefkit-0.6.3/xrefkit/plan_markdown.py +330 -0
- xrefkit-0.6.3/xrefkit/plan_observation.py +414 -0
- xrefkit-0.6.3/xrefkit/reporting.py +444 -0
- xrefkit-0.6.3/xrefkit/reporting_profiles.py +170 -0
- xrefkit-0.6.3/xrefkit/repository_skills.py +259 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/skill_definition_governance.py +2 -1
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/skillmeta.py +40 -3
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/skillrun.py +54 -4
- xrefkit-0.6.3/xrefkit/work_management.py +614 -0
- xrefkit-0.6.3/xrefkit/work_management_view.py +155 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/xref.py +36 -7
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit.egg-info/PKG-INFO +37 -1
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit.egg-info/SOURCES.txt +35 -0
- xrefkit-0.6.1/tests/test_constraint_derivation_selected_family.py +0 -44
- {xrefkit-0.6.1 → xrefkit-0.6.3}/LICENSE +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/setup.cfg +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_attention_pet.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_attention_pet_client_protocol.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_attention_pet_codex_session.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_attention_pet_fit.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_boundary_analysis.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_calibration_lint.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_check_skill_knowledge_xids.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_cli.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_collect_analyzer_sarif.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_convert_to_xrefkit_skill.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_cs_scope_probe.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_csharp_commonality.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_csharp_naming_profile.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_ctx.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_cutover_readiness.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_decision_trace.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_embedded_startup_pack.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_error_policy_audit.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_error_policy_locator.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_execution_binding.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_existing_skill_definition_batch.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_fm_multiroot.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_gate.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_gateway.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_gateway_mcp.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_gateway_skill_adapter.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_gateway_work_items.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_goal_desired_state.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_host_precheck.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_human_evaluation.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_implementation_review_selected_family.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_inbound_uploads.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_instruction_workflow.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_legacy_migration.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_mcp_package_routing.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_mcp_setup.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_ownership.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_packmeta.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_project_quality_baseline.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_resource_provider.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_runtime_contracts.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_sarif_to_locator.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_skill_definition.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_skill_definition_governance.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_skill_maturity_return.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_skill_runtime_audit.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_skillmeta.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_skills_sync.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_structure_catalog.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_subagent_startup.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_subagent_startup_boundaries.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_wbs.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_xref.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_xrefkit_instance.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_xrefkit_tools.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_xrefkit_v2_discovery.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_xrefkit_v2_models.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/tests/test_xrefkit_v2_pipeline.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/__main__.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/attention_pet/__init__.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/attention_pet/__main__.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/attention_pet/client.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/attention_pet/client_protocol.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/attention_pet/codex_session.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/attention_pet/evaluator.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/attention_pet/model.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/attention_pet/presentation.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/attention_pet/profiles.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/attention_pet/scenarios.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/attention_pet/server.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/attention_pet/store.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/boundary_analysis.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/catalog_cli.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/contracts.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/ctx.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/decision_trace.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/discovery.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/execution_binding.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/execution_binding_cli.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/gate.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/gateway.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/goalstate.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/hashing.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/host_precheck.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/import_skill.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/instance.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/loaders.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/mcp/__init__.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/mcp/bootstrap.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/mcp/client_cache.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/mcp/client_flow.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/mcp/context_registry.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/mcp/context_token.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/mcp/contracts.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/mcp/contribution_adoption.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/mcp/dist.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/mcp/gateway.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/mcp/inbound_uploads.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/mcp/legacy_migration.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/mcp/ownership.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/mcp/repository.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/mcp/setup.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/mcp/skill_maturity.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/mcp/startup_contract_pack.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/mcp_tools.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/models/__init__.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/models/common.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/models/effective_bundle.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/models/human_evaluation.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/models/local_manifest.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/models/package_manifest.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/models/run_log.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/models/server_config.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/models/skill_definition.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/operations_cli.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/ownership.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/registry.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/resolver.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/resource_provider.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/resources/attention_pet/client-state.schema.json +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/resources/attention_pet/pet.css +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/resources/attention_pet/pet.html +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/resources/attention_pet/pet.js +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/resources/base/contracts.json +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/resources/base/current.json +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/resources/base/generations/7a682a5272907354/contracts.json +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/resources/base/generations/7a682a5272907354/model_body.md +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/resources/base/generations/9929294385ccb7b0/contracts.json +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/resources/base/generations/9929294385ccb7b0/model_body.md +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/resources/base/model_body.md +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/resources/base/startup_sources/000_agent_entry.md +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/resources/base/startup_sources/011_startup_xref_routing.md +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/resources/base/startup_sources/015_shared_memory_operations.md +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/resources/base/startup_sources/016_uncertainty_protocol.md +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/resources/base/startup_sources/017_base_and_xref_layering.md +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/resources/base/startup_sources/053_context_direction_security_guard.md +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/runlog.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/skill_definition.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/skill_definition_catalog.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/skills_sync.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/structure_catalog.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/subagent_startup.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/tools/__init__.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/tools/__main__.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/v2_cli.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/wbs.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit/workspace.py +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit.egg-info/dependency_links.txt +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit.egg-info/entry_points.txt +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit.egg-info/requires.txt +0 -0
- {xrefkit-0.6.1 → xrefkit-0.6.3}/xrefkit.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: xrefkit
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.3
|
|
4
4
|
Summary: Portable XID, Skill, Knowledge, workflow, and MCP runtime for XRefKit
|
|
5
5
|
Author: synthaicode
|
|
6
6
|
License: MIT License
|
|
@@ -186,3 +186,39 @@ XRefKit does not require provider API keys to explore or install the package.
|
|
|
186
186
|
Do not commit secrets, API keys, access tokens, `.env` files, or provider
|
|
187
187
|
credentials. Authenticate external AI tools through their official provider
|
|
188
188
|
mechanisms.
|
|
189
|
+
|
|
190
|
+
## Repository Skill adoption and scoped source-analysis knowledge
|
|
191
|
+
|
|
192
|
+
This repository uses the audited canonical Skill sources listed in
|
|
193
|
+
`skills/repository_adoption.json`. Legacy source identities remain aliases;
|
|
194
|
+
external legacy split Skills and YAML Skill Packages remain supported. See
|
|
195
|
+
[SkillDefinition adoption](docs/core/contracts/096_skill_definition_contract.md#xid-E6A19D4B72C3).
|
|
196
|
+
The source-analysis common XID remains stable and routes coherent criteria
|
|
197
|
+
fragments on demand. Narrow tasks avoid unrelated bodies; full reviews retain
|
|
198
|
+
every required axis. No similarity-based knowledge merge or deletion occurs.
|
|
199
|
+
|
|
200
|
+
## Public website release metadata
|
|
201
|
+
|
|
202
|
+
The Pages workflow builds from `main`, verifies the checked-in site against
|
|
203
|
+
`site/sources`, then fetches GitHub's latest published stable release and runs
|
|
204
|
+
`tools/site_release_metadata.py` on the deployment artifact. It updates the
|
|
205
|
+
homepage version, UTC publication date and release link, plus the foundation
|
|
206
|
+
page's release-source link. The checked-in HTML is an offline snapshot; it is
|
|
207
|
+
not rewritten or committed by deployment. Editorial development notes are
|
|
208
|
+
maintained separately and are not inferred from release metadata.
|
|
209
|
+
|
|
210
|
+
Pages runs on main pushes, release publication/changes, manual dispatch, and
|
|
211
|
+
successful repository push runs of `python-package`. The last trigger covers
|
|
212
|
+
releases created using `GITHUB_TOKEN`, which do not trigger another release
|
|
213
|
+
workflow. Deployment always checks out main, never a workflow-run/PR artifact.
|
|
214
|
+
API failure, a draft/prerelease, an unexpected version tag, or missing page
|
|
215
|
+
markers stops publication and leaves the previous deployed site in place.
|
|
216
|
+
|
|
217
|
+
To reproduce the rendering after building a site into a separate directory:
|
|
218
|
+
|
|
219
|
+
```sh
|
|
220
|
+
gh api repos/synthaicode/XRefKit/releases/latest > release.json
|
|
221
|
+
python tools/site_release_metadata.py --site .generated-site --release-json release.json --repository synthaicode/XRefKit
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Use the Pages workflow's manual dispatch to retry a failed metadata fetch.
|
|
@@ -147,3 +147,39 @@ XRefKit does not require provider API keys to explore or install the package.
|
|
|
147
147
|
Do not commit secrets, API keys, access tokens, `.env` files, or provider
|
|
148
148
|
credentials. Authenticate external AI tools through their official provider
|
|
149
149
|
mechanisms.
|
|
150
|
+
|
|
151
|
+
## Repository Skill adoption and scoped source-analysis knowledge
|
|
152
|
+
|
|
153
|
+
This repository uses the audited canonical Skill sources listed in
|
|
154
|
+
`skills/repository_adoption.json`. Legacy source identities remain aliases;
|
|
155
|
+
external legacy split Skills and YAML Skill Packages remain supported. See
|
|
156
|
+
[SkillDefinition adoption](docs/core/contracts/096_skill_definition_contract.md#xid-E6A19D4B72C3).
|
|
157
|
+
The source-analysis common XID remains stable and routes coherent criteria
|
|
158
|
+
fragments on demand. Narrow tasks avoid unrelated bodies; full reviews retain
|
|
159
|
+
every required axis. No similarity-based knowledge merge or deletion occurs.
|
|
160
|
+
|
|
161
|
+
## Public website release metadata
|
|
162
|
+
|
|
163
|
+
The Pages workflow builds from `main`, verifies the checked-in site against
|
|
164
|
+
`site/sources`, then fetches GitHub's latest published stable release and runs
|
|
165
|
+
`tools/site_release_metadata.py` on the deployment artifact. It updates the
|
|
166
|
+
homepage version, UTC publication date and release link, plus the foundation
|
|
167
|
+
page's release-source link. The checked-in HTML is an offline snapshot; it is
|
|
168
|
+
not rewritten or committed by deployment. Editorial development notes are
|
|
169
|
+
maintained separately and are not inferred from release metadata.
|
|
170
|
+
|
|
171
|
+
Pages runs on main pushes, release publication/changes, manual dispatch, and
|
|
172
|
+
successful repository push runs of `python-package`. The last trigger covers
|
|
173
|
+
releases created using `GITHUB_TOKEN`, which do not trigger another release
|
|
174
|
+
workflow. Deployment always checks out main, never a workflow-run/PR artifact.
|
|
175
|
+
API failure, a draft/prerelease, an unexpected version tag, or missing page
|
|
176
|
+
markers stops publication and leaves the previous deployed site in place.
|
|
177
|
+
|
|
178
|
+
To reproduce the rendering after building a site into a separate directory:
|
|
179
|
+
|
|
180
|
+
```sh
|
|
181
|
+
gh api repos/synthaicode/XRefKit/releases/latest > release.json
|
|
182
|
+
python tools/site_release_metadata.py --site .generated-site --release-json release.json --repository synthaicode/XRefKit
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Use the Pages workflow's manual dispatch to retry a failed metadata fetch.
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from repository_skill_receipts import assert_preserved_source_boundary
|
|
2
|
+
from repository_skill_receipts import assert_legacy_receipt
|
|
1
3
|
from pathlib import Path
|
|
2
4
|
|
|
3
5
|
import pytest
|
|
@@ -25,9 +27,8 @@ def test_artifact_v1_parse_concrete_metadata_and_legacy(directory, skill_id, xid
|
|
|
25
27
|
assert set(metadata["aliases"]) == {body_xid, meta_xid}
|
|
26
28
|
assert metadata["inputs"] and metadata["outputs"]
|
|
27
29
|
assert metadata["control_refs"] == []
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
assert "skill_doc: `./SKILL.md`" in (repo / relative.parent / "meta.md").read_text()
|
|
30
|
+
assert_preserved_source_boundary(definition)
|
|
31
|
+
assert_legacy_receipt(repo / relative.parent / 'meta.md')
|
|
31
32
|
|
|
32
33
|
|
|
33
34
|
def test_artifact_v1_explicit_batch_selection_and_knowledge_resolution():
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import copy
|
|
3
|
+
import hashlib
|
|
4
|
+
import io
|
|
5
|
+
import json
|
|
6
|
+
import tempfile
|
|
7
|
+
import unittest
|
|
8
|
+
from contextlib import redirect_stdout, redirect_stderr
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from urllib.error import HTTPError, URLError
|
|
11
|
+
from unittest.mock import patch
|
|
12
|
+
|
|
13
|
+
from xrefkit.azure_connection import MAX_BYTES, _NoRedirect, load_connection, main, read_check, register_connection, validate_profile
|
|
14
|
+
from xrefkit.work_management import register_workspace
|
|
15
|
+
|
|
16
|
+
CANARY = "canary-PAT-not-a-real-credential-abc123"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Response:
|
|
20
|
+
def __init__(self, request, body=None, *, content_type="application/json", status=200, url=None):
|
|
21
|
+
self.url = request.full_url if url is None else url
|
|
22
|
+
self.headers = {"Content-Type": content_type}
|
|
23
|
+
self.status = status
|
|
24
|
+
self.body = json.dumps({"id": 10, "rev": 3, "fields": {"System.TeamProject": "AI01-Scrum", "System.WorkItemType": "Product Backlog Item", "System.State": "New"}}).encode() if body is None else body
|
|
25
|
+
self.closed = False
|
|
26
|
+
|
|
27
|
+
def geturl(self):
|
|
28
|
+
return self.url
|
|
29
|
+
|
|
30
|
+
def read(self, size):
|
|
31
|
+
return self.body[:size]
|
|
32
|
+
|
|
33
|
+
def __enter__(self):
|
|
34
|
+
return self
|
|
35
|
+
|
|
36
|
+
def __exit__(self, *args):
|
|
37
|
+
self.closed = True
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class AzureConnectionTests(unittest.TestCase):
|
|
41
|
+
def setUp(self):
|
|
42
|
+
self.temp = tempfile.TemporaryDirectory()
|
|
43
|
+
self.addCleanup(self.temp.cleanup)
|
|
44
|
+
self.root = Path(self.temp.name).resolve()
|
|
45
|
+
register_workspace(self.root, {"schema_version": 1, "workspace_id": "local", "title": "Local", "workspace_root": "."})
|
|
46
|
+
self.profile = {"schema_version": 1, "workspace_id": "local", "connection_id": "test", "service": "azure_devops_services", "organization": "seijim0pattern01", "project": "AI01-Scrum", "environment": "test", "auth": {"kind": "pat_env", "env_var": "EXPLICIT_TEST_PAT"}, "allowed_operations": ["read_work_item"], "allowed_item_ids": [10]}
|
|
47
|
+
|
|
48
|
+
def register(self, profile=None):
|
|
49
|
+
return register_connection(self.root, "local", self.profile if profile is None else profile)
|
|
50
|
+
|
|
51
|
+
def check(self):
|
|
52
|
+
return read_check(self.root, "local", "test", 10)
|
|
53
|
+
|
|
54
|
+
def test_registration_is_local_immutable_and_no_clobber(self):
|
|
55
|
+
with patch("xrefkit.azure_connection.build_opener") as network:
|
|
56
|
+
first = self.register()
|
|
57
|
+
self.assertTrue(self.register()["replayed"])
|
|
58
|
+
network.assert_not_called()
|
|
59
|
+
before = Path(first["output"]).read_bytes()
|
|
60
|
+
changed = {**self.profile, "project": "other"}
|
|
61
|
+
with self.assertRaises(ValueError):
|
|
62
|
+
self.register(changed)
|
|
63
|
+
self.assertEqual(before, Path(first["output"]).read_bytes())
|
|
64
|
+
other = {**self.profile, "connection_id": "next"}
|
|
65
|
+
target = Path(first["output"]).parent / (hashlib.sha256(b"local\0next").hexdigest()[:24] + ".json")
|
|
66
|
+
target.write_text(json.dumps({**other, "connection_id": "unrelated"}), encoding="utf-8")
|
|
67
|
+
before = target.read_bytes()
|
|
68
|
+
with self.assertRaises(ValueError):
|
|
69
|
+
self.register(other)
|
|
70
|
+
self.assertEqual(before, target.read_bytes())
|
|
71
|
+
|
|
72
|
+
def test_strict_schema_scope_types_and_secret_fields(self):
|
|
73
|
+
cases = [{**self.profile, "pat": CANARY}, {**self.profile, "schema_version": True}, {**self.profile, "allowed_item_ids": [True]}, {**self.profile, "allowed_item_ids": [10, 10]}, {**self.profile, "allowed_operations": ["update_work_item"]}, {**self.profile, "auth": {"kind": "pat_env", "env_var": "BAD-NAME"}}, {**self.profile, "project": "../elsewhere"}, {**self.profile, "organization": "example.test/path"}]
|
|
74
|
+
for value in cases:
|
|
75
|
+
with self.subTest(value=value), self.assertRaises(ValueError) as error:
|
|
76
|
+
validate_profile(value)
|
|
77
|
+
self.assertNotIn(CANARY, str(error.exception))
|
|
78
|
+
|
|
79
|
+
def test_selected_workspace_never_falls_back(self):
|
|
80
|
+
child = self.root / "client"
|
|
81
|
+
child.mkdir()
|
|
82
|
+
register_workspace(self.root, {"schema_version": 1, "workspace_id": "client", "title": "Client", "workspace_root": "client"})
|
|
83
|
+
self.register()
|
|
84
|
+
with self.assertRaises(ValueError):
|
|
85
|
+
load_connection(self.root, "client", "test")
|
|
86
|
+
other = {**self.profile, "workspace_id": "client", "project": "other"}
|
|
87
|
+
register_connection(self.root, "client", other)
|
|
88
|
+
self.assertEqual("other", load_connection(self.root, "client", "test")["project"])
|
|
89
|
+
self.assertEqual("AI01-Scrum", load_connection(self.root, "local", "test")["project"])
|
|
90
|
+
with self.assertRaises(ValueError):
|
|
91
|
+
self.register(other)
|
|
92
|
+
|
|
93
|
+
def test_duplicate_malformed_and_oversize_profile_fail_closed(self):
|
|
94
|
+
first = self.register()
|
|
95
|
+
target = Path(first["output"])
|
|
96
|
+
target.with_name("duplicate.json").write_bytes(target.read_bytes())
|
|
97
|
+
with self.assertRaises(ValueError):
|
|
98
|
+
load_connection(self.root, "local", "test")
|
|
99
|
+
target.with_name("duplicate.json").unlink()
|
|
100
|
+
for body in (b'{"secret":"' + CANARY.encode() + b'","secret":"duplicate"}', b"x" * (MAX_BYTES + 1)):
|
|
101
|
+
target.write_bytes(body)
|
|
102
|
+
result = self.check()
|
|
103
|
+
self.assertFalse(result["configuration_valid"])
|
|
104
|
+
self.assertNotIn(CANARY, json.dumps(result))
|
|
105
|
+
|
|
106
|
+
def test_scope_checks_happen_before_env_lookup_and_network(self):
|
|
107
|
+
for change in ({"environment": "production"}, {"allowed_operations": []}, {"allowed_item_ids": []}):
|
|
108
|
+
self.profile.update(change)
|
|
109
|
+
saved = self.register()
|
|
110
|
+
with patch("xrefkit.azure_connection.os.environ.get") as env, patch("xrefkit.azure_connection.build_opener") as network:
|
|
111
|
+
result = self.check()
|
|
112
|
+
self.assertEqual("test_read_scope_rejected", result["diagnostic_code"])
|
|
113
|
+
env.assert_not_called()
|
|
114
|
+
network.assert_not_called()
|
|
115
|
+
Path(saved["output"]).unlink()
|
|
116
|
+
self.profile.update(environment="test", allowed_operations=["read_work_item"], allowed_item_ids=[10])
|
|
117
|
+
|
|
118
|
+
def test_missing_named_credential_has_no_other_env_fallback(self):
|
|
119
|
+
self.register()
|
|
120
|
+
with patch.dict("os.environ", {"AZURE_DEVOPS_PAT": CANARY}, clear=True), patch("xrefkit.azure_connection.build_opener") as network:
|
|
121
|
+
result = self.check()
|
|
122
|
+
self.assertEqual("credential_unavailable", result["diagnostic_code"])
|
|
123
|
+
self.assertFalse(result["network_attempted"])
|
|
124
|
+
network.assert_not_called()
|
|
125
|
+
|
|
126
|
+
def test_matching_read_sends_one_get_and_whitelists_only_safe_fields(self):
|
|
127
|
+
self.register()
|
|
128
|
+
response = None
|
|
129
|
+
def request(req, timeout):
|
|
130
|
+
nonlocal response
|
|
131
|
+
self.assertEqual("GET", req.get_method())
|
|
132
|
+
self.assertEqual(30, timeout)
|
|
133
|
+
self.assertIn("https://dev.azure.com/seijim0pattern01/AI01-Scrum/_apis/wit/workitems/10?", req.full_url)
|
|
134
|
+
self.assertIn("api-version=7.1", req.full_url)
|
|
135
|
+
self.assertEqual("Basic " + base64.b64encode((":" + CANARY).encode()).decode(), req.get_header("Authorization"))
|
|
136
|
+
response = Response(req)
|
|
137
|
+
return response
|
|
138
|
+
with patch.dict("os.environ", {"EXPLICIT_TEST_PAT": CANARY}), patch("xrefkit.azure_connection.build_opener") as builder:
|
|
139
|
+
builder.return_value.open.side_effect = request
|
|
140
|
+
result = self.check()
|
|
141
|
+
builder.return_value.open.assert_called_once()
|
|
142
|
+
self.assertTrue(response.closed)
|
|
143
|
+
self.assertTrue(result["read_verified"])
|
|
144
|
+
self.assertFalse(result["write_permission_verified"])
|
|
145
|
+
self.assertEqual(3, result["observed_revision"])
|
|
146
|
+
self.assertNotIn(CANARY, json.dumps(result))
|
|
147
|
+
self.assertNotIn("Authorization", json.dumps(result))
|
|
148
|
+
self.assertEqual({}, builder.call_args.args[0].proxies)
|
|
149
|
+
self.assertIsInstance(builder.call_args.args[1], _NoRedirect)
|
|
150
|
+
|
|
151
|
+
def test_http_failures_and_redirects_are_sanitized_without_retry(self):
|
|
152
|
+
self.register()
|
|
153
|
+
for status, code in ((401, "authentication_rejected"), (403, "access_forbidden"), (404, "unavailable_or_not_visible"), (302, "redirect_rejected"), (307, "redirect_rejected"), (429, "rate_limited"), (503, "server_failure")):
|
|
154
|
+
with self.subTest(status=status), patch.dict("os.environ", {"EXPLICIT_TEST_PAT": CANARY}), patch("xrefkit.azure_connection.build_opener") as builder:
|
|
155
|
+
builder.return_value.open.side_effect = HTTPError("https://evil.test/" + CANARY, status, CANARY, {}, io.BytesIO(CANARY.encode()))
|
|
156
|
+
result = self.check()
|
|
157
|
+
self.assertEqual(code, result["diagnostic_code"])
|
|
158
|
+
self.assertNotIn(CANARY, json.dumps(result))
|
|
159
|
+
builder.return_value.open.assert_called_once()
|
|
160
|
+
self.assertIsNone(_NoRedirect().redirect_request(None, None, 302, "", {}, "https://other.test/"))
|
|
161
|
+
|
|
162
|
+
def test_malformed_mismatched_and_secret_echo_responses_are_not_verified(self):
|
|
163
|
+
self.register()
|
|
164
|
+
base = {"id": 10, "rev": 3, "fields": {"System.TeamProject": "AI01-Scrum", "System.WorkItemType": "Product Backlog Item", "System.State": "New"}}
|
|
165
|
+
echo = copy.deepcopy(base)
|
|
166
|
+
echo["fields"]["System.State"] = CANARY
|
|
167
|
+
for body in (b"invalid " + CANARY.encode(), b"x" * (MAX_BYTES + 1), json.dumps({**base, "id": 11}).encode(), json.dumps({**base, "fields": {"System.TeamProject": "other"}}).encode(), json.dumps(echo).encode()):
|
|
168
|
+
with self.subTest(size=len(body)), patch.dict("os.environ", {"EXPLICIT_TEST_PAT": CANARY}), patch("xrefkit.azure_connection.build_opener") as builder:
|
|
169
|
+
builder.return_value.open.side_effect = lambda req, timeout: Response(req, body)
|
|
170
|
+
result = self.check()
|
|
171
|
+
self.assertFalse(result["read_verified"])
|
|
172
|
+
self.assertNotIn(CANARY, json.dumps(result))
|
|
173
|
+
|
|
174
|
+
def test_network_timeout_nonjson_and_unexpected_final_url_are_controlled(self):
|
|
175
|
+
self.register()
|
|
176
|
+
for error in (TimeoutError(CANARY), URLError(CANARY)):
|
|
177
|
+
with patch.dict("os.environ", {"EXPLICIT_TEST_PAT": CANARY}), patch("xrefkit.azure_connection.build_opener") as builder:
|
|
178
|
+
builder.return_value.open.side_effect = error
|
|
179
|
+
self.assertEqual("network_request_failed", self.check()["diagnostic_code"])
|
|
180
|
+
for changes, code in (({"content_type": "text/html"}, "response_not_json"), ({"url": "https://evil.test"}, "response_destination_mismatch")):
|
|
181
|
+
with patch.dict("os.environ", {"EXPLICIT_TEST_PAT": CANARY}), patch("xrefkit.azure_connection.build_opener") as builder:
|
|
182
|
+
builder.return_value.open.side_effect = lambda req, timeout: Response(req, **changes)
|
|
183
|
+
self.assertEqual(code, self.check()["diagnostic_code"])
|
|
184
|
+
|
|
185
|
+
def test_cli_never_echoes_secret_or_server_error_text(self):
|
|
186
|
+
self.register()
|
|
187
|
+
output = io.StringIO()
|
|
188
|
+
with redirect_stdout(output), patch.dict("os.environ", {"EXPLICIT_TEST_PAT": CANARY}), patch("xrefkit.azure_connection.build_opener") as builder:
|
|
189
|
+
builder.return_value.open.side_effect = HTTPError(CANARY, 401, CANARY, {}, io.BytesIO(CANARY.encode()))
|
|
190
|
+
status = main(["read-check", "--root", str(self.root), "--workspace-id", "local", "--connection-id", "test", "--item-id", "10"])
|
|
191
|
+
self.assertEqual(1, status)
|
|
192
|
+
self.assertNotIn(CANARY, output.getvalue())
|
|
193
|
+
self.assertEqual("authentication_rejected", json.loads(output.getvalue())["diagnostic_code"])
|
|
194
|
+
|
|
195
|
+
def test_invalid_cli_arguments_never_echo_values_to_stdout_or_stderr(self):
|
|
196
|
+
arguments = ["read-check", "--root", str(self.root), "--workspace-id", "local", "--connection-id", "test"]
|
|
197
|
+
for suffix in (["--item-id", "10", "--pat", CANARY], ["--item-id", CANARY]):
|
|
198
|
+
stdout, stderr = io.StringIO(), io.StringIO()
|
|
199
|
+
with redirect_stdout(stdout), redirect_stderr(stderr):
|
|
200
|
+
status = main(arguments + suffix)
|
|
201
|
+
self.assertEqual(1, status)
|
|
202
|
+
self.assertNotIn(CANARY, stdout.getvalue() + stderr.getvalue())
|
|
203
|
+
self.assertEqual("arguments_invalid", json.loads(stdout.getvalue())["diagnostic_code"])
|
|
204
|
+
|
|
205
|
+
def test_escaping_connection_directory_is_rejected(self):
|
|
206
|
+
directory = self.root / "work/integrations"
|
|
207
|
+
directory.mkdir(parents=True)
|
|
208
|
+
with tempfile.TemporaryDirectory() as outside:
|
|
209
|
+
try:
|
|
210
|
+
(directory / "connections").symlink_to(outside, target_is_directory=True)
|
|
211
|
+
except OSError:
|
|
212
|
+
self.skipTest("Windows symlink privileges unavailable")
|
|
213
|
+
with self.assertRaises(ValueError):
|
|
214
|
+
self.register()
|