Block conflicting extension write selectors
This commit is contained in:
@@ -20992,6 +20992,14 @@ def test_metadata_write_active_form_target_auto_prepares_when_apply_allowed(monk
|
||||
def test_metadata_write_missing_form_target_auto_prepares_and_retries(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
calls: dict[str, int] = {"apply": 0}
|
||||
seen: dict[str, Any] = {}
|
||||
monkeypatch.setattr(
|
||||
adapter_server,
|
||||
"extension_filter_to_guid",
|
||||
lambda base_id, extension, method: (
|
||||
"fb26cf42-7609-11f1-828f-005056b0d483",
|
||||
None,
|
||||
),
|
||||
)
|
||||
|
||||
def fake_apply(payload: dict[str, Any]) -> dict[str, Any]:
|
||||
calls["apply"] += 1
|
||||
@@ -21856,6 +21864,104 @@ def test_write_gate_context_does_not_fall_back_to_base_for_unknown_extension(
|
||||
assert adapter_server.repository_control.development_layer_id(result) == "extension:unresolved"
|
||||
|
||||
|
||||
def test_write_gate_context_rejects_conflicting_extension_name_and_guid(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
name_guid = "fb26cf42-7609-11f1-828f-005056b0d483"
|
||||
supplied_guid = "11111111-1111-1111-1111-111111111111"
|
||||
monkeypatch.setattr(
|
||||
adapter_server,
|
||||
"extension_filter_to_guid",
|
||||
lambda base_id, extension, method: (name_guid, None),
|
||||
)
|
||||
|
||||
result = adapter_server.resolve_write_gate_context(
|
||||
{
|
||||
"base_id": "upo_test",
|
||||
"extension_guid": supplied_guid,
|
||||
"target": {
|
||||
"kind": "form",
|
||||
"extension": "test2",
|
||||
"ref": "Catalog.test2",
|
||||
"form": "t_Форма",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
resolution = result["development_layer_resolution"]
|
||||
assert "extension_guid" not in result
|
||||
assert "extension_guid" not in result["target"]
|
||||
assert resolution["status"] == "conflict"
|
||||
assert resolution["layer_id"] == "extension:unresolved"
|
||||
assert resolution["extension"] == {
|
||||
"name": "test2",
|
||||
"supplied_guid": supplied_guid,
|
||||
}
|
||||
assert resolution["diagnostics"]["error"] == "extension_selector_conflict"
|
||||
assert resolution["diagnostics"]["resolved_extension_guid"] == name_guid
|
||||
|
||||
|
||||
def test_repository_apply_gate_blocks_unresolved_extension_before_policy_gates(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
def must_not_run(_payload: dict[str, Any]) -> dict[str, Any]:
|
||||
raise AssertionError("repository/support policy gates must not authorize an unresolved extension layer")
|
||||
|
||||
monkeypatch.setattr(adapter_server.repository_control, "write_gate", must_not_run)
|
||||
monkeypatch.setattr(adapter_server, "live_sql_support_gate", must_not_run)
|
||||
|
||||
result = adapter_server.repository_apply_gate(
|
||||
{
|
||||
"base_id": "upo_test",
|
||||
"development_layer_resolution": {
|
||||
"status": "conflict",
|
||||
"layer_id": "extension:unresolved",
|
||||
"diagnostics": {"error": "extension_selector_conflict"},
|
||||
},
|
||||
},
|
||||
"metadata.write",
|
||||
"apply",
|
||||
)
|
||||
|
||||
assert result["status"] == "blocked"
|
||||
assert result["error"] == "extension_selector_conflict"
|
||||
assert result["layer_id"] == "extension:unresolved"
|
||||
|
||||
|
||||
def test_metadata_write_apply_blocks_conflicting_extension_name_and_guid(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
monkeypatch.setattr(
|
||||
adapter_server,
|
||||
"extension_filter_to_guid",
|
||||
lambda base_id, extension, method: (
|
||||
"fb26cf42-7609-11f1-828f-005056b0d483",
|
||||
None,
|
||||
),
|
||||
)
|
||||
|
||||
result = adapter_server.metadata_write(
|
||||
{
|
||||
"base_id": "upo_test",
|
||||
"extension_guid": "11111111-1111-1111-1111-111111111111",
|
||||
"target": {
|
||||
"kind": "form",
|
||||
"extension": "test2",
|
||||
"ref": "Catalog.test2",
|
||||
"form": "t_Форма",
|
||||
"command": "ЗаменаДомена",
|
||||
},
|
||||
"edits": [{"property": "Заголовок", "value": "Новое имя"}],
|
||||
"mode": "apply",
|
||||
}
|
||||
)
|
||||
|
||||
assert result["schema"] == "onec_repository_write_gate.v1"
|
||||
assert result["status"] == "blocked"
|
||||
assert result["error"] == "extension_selector_conflict"
|
||||
assert result["development_layer_resolution"]["status"] == "conflict"
|
||||
|
||||
|
||||
def test_metadata_write_preflight_routes_public_extension_form_gates_to_extension_layer(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
@@ -21928,6 +22034,84 @@ def test_metadata_write_preflight_routes_public_extension_form_gates_to_extensio
|
||||
assert captured_layers == [expected_layer, expected_layer]
|
||||
|
||||
|
||||
def test_metadata_write_preflight_blocks_conflicting_extension_name_and_guid(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
name_guid = "fb26cf42-7609-11f1-828f-005056b0d483"
|
||||
supplied_guid = "11111111-1111-1111-1111-111111111111"
|
||||
monkeypatch.setattr(
|
||||
adapter_server,
|
||||
"extension_filter_to_guid",
|
||||
lambda base_id, extension, method: (name_guid, None),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
adapter_server,
|
||||
"metadata_form_write_target_resolve",
|
||||
lambda payload: {
|
||||
"status": "ok",
|
||||
"source": {
|
||||
"table": "ConfigCASSave",
|
||||
"file_name": f"{name_guid}__form-guid.0",
|
||||
},
|
||||
"counts": {"matches": 1},
|
||||
},
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
adapter_server,
|
||||
"metadata_saved_state_diff",
|
||||
lambda payload: {
|
||||
"status": "changed",
|
||||
"target": {"table": payload["table"], "file_name": payload["file_name"]},
|
||||
"freshness": {
|
||||
"source": "live_sql",
|
||||
"status": "live_sql_verified",
|
||||
"verified_against_sql": True,
|
||||
},
|
||||
},
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
adapter_server.repository_control,
|
||||
"write_gate",
|
||||
lambda payload: {
|
||||
"status": "not_configured",
|
||||
"allowed": True,
|
||||
"layer_id": adapter_server.repository_control.development_layer_id(payload),
|
||||
},
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
adapter_server,
|
||||
"live_sql_support_gate",
|
||||
lambda payload: {
|
||||
"status": "support_not_configured_legacy",
|
||||
"allowed": True,
|
||||
"layer_id": adapter_server.repository_control.development_layer_id(payload),
|
||||
},
|
||||
)
|
||||
|
||||
result = adapter_server.metadata_write_preflight(
|
||||
{
|
||||
"base_id": "upo_test",
|
||||
"extension_guid": supplied_guid,
|
||||
"target": {
|
||||
"kind": "form",
|
||||
"extension": "test2",
|
||||
"ref": "Catalog.test2",
|
||||
"form": "t_Форма",
|
||||
"command": "ЗаменаДомена",
|
||||
},
|
||||
"edits": [{"property": "Заголовок", "value": "Новое имя"}],
|
||||
"resolve_origin": False,
|
||||
}
|
||||
)
|
||||
|
||||
assert result["status"] == "blocked"
|
||||
assert result["allowed"] is False
|
||||
assert result["repository"]["allowed"] is True
|
||||
assert result["support"]["allowed"] is True
|
||||
assert result["development_layer_resolution"]["status"] == "conflict"
|
||||
assert result["development_layer_resolution"]["diagnostics"]["error"] == "extension_selector_conflict"
|
||||
|
||||
|
||||
def test_metadata_write_plan_help_describes_name_first_form_and_module_targets() -> None:
|
||||
methods = {
|
||||
row["name"]: row
|
||||
@@ -26459,6 +26643,14 @@ def test_metadata_write_missing_module_target_exposes_prepare_plan(monkeypatch:
|
||||
def test_metadata_write_missing_module_target_auto_prepares_and_retries(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
calls: dict[str, int] = {"search": 0}
|
||||
seen: dict[str, Any] = {}
|
||||
monkeypatch.setattr(
|
||||
adapter_server,
|
||||
"extension_filter_to_guid",
|
||||
lambda base_id, extension, method: (
|
||||
"fb26cf42-7609-11f1-828f-005056b0d483",
|
||||
None,
|
||||
),
|
||||
)
|
||||
|
||||
def fake_search(payload: dict[str, Any]) -> dict[str, Any]:
|
||||
calls["search"] += 1
|
||||
|
||||
@@ -112,6 +112,22 @@ def test_public_extension_form_candidate_is_name_first_and_prefers_title() -> No
|
||||
}
|
||||
|
||||
|
||||
def test_different_extension_guid_changes_only_last_hex_digit() -> None:
|
||||
assert (
|
||||
smoke.different_extension_guid(
|
||||
"extension:fb26cf42-7609-11f1-828f-005056b0d483"
|
||||
)
|
||||
== "fb26cf42-7609-11f1-828f-005056b0d480"
|
||||
)
|
||||
assert (
|
||||
smoke.different_extension_guid(
|
||||
"extension:fb26cf42-7609-11f1-828f-005056b0d480"
|
||||
)
|
||||
== "fb26cf42-7609-11f1-828f-005056b0d481"
|
||||
)
|
||||
assert smoke.different_extension_guid("base") is None
|
||||
|
||||
|
||||
def test_name_first_extension_form_preflight_rejects_base_gate_layer(monkeypatch) -> None:
|
||||
def fake_rpc_call(
|
||||
_endpoint_url: str,
|
||||
|
||||
Reference in New Issue
Block a user