generated from coulomb/repo-seed
chore(consistency): sync task status from DB [auto]
Updated by fix-consistency on 2026-05-07: - update .custodian-brief.md for open-cmis-tck
This commit is contained in:
@@ -117,12 +117,43 @@ def run(context: dict[str, Any]) -> dict[str, Any]:
|
||||
}
|
||||
|
||||
facts["json_detected"] = True
|
||||
facts.update(_repository_facts(parsed))
|
||||
repository_facts = _repository_facts(parsed, context)
|
||||
facts.update(repository_facts)
|
||||
unsupported = [
|
||||
item
|
||||
for item in repository_facts.get("capability_posture", [])
|
||||
if item.get("status") == "unsupported"
|
||||
]
|
||||
expected_gaps = [
|
||||
item
|
||||
for item in repository_facts.get("capability_posture", [])
|
||||
if item.get("status") == "expected_gap"
|
||||
]
|
||||
if unsupported:
|
||||
return {
|
||||
"result": "fail",
|
||||
"observations": [
|
||||
"CMIS Browser Binding endpoint is reachable, but declared capabilities are not supported by repository capability flags.",
|
||||
"Unsupported declared requirements: "
|
||||
+ ", ".join(item["requirement_ref"] for item in unsupported)
|
||||
+ ".",
|
||||
],
|
||||
"facts": facts,
|
||||
"artifact_refs": artifact_refs,
|
||||
}
|
||||
|
||||
observations = [
|
||||
"CMIS Browser Binding endpoint is reachable and returned parseable JSON."
|
||||
]
|
||||
if expected_gaps:
|
||||
observations.append(
|
||||
"Unsupported optional capabilities were accepted as known gaps: "
|
||||
+ ", ".join(item["requirement_ref"] for item in expected_gaps)
|
||||
+ "."
|
||||
)
|
||||
return {
|
||||
"result": "pass",
|
||||
"observations": [
|
||||
"CMIS Browser Binding endpoint is reachable and returned parseable JSON."
|
||||
],
|
||||
"observations": observations,
|
||||
"facts": facts,
|
||||
"artifact_refs": artifact_refs,
|
||||
}
|
||||
@@ -150,29 +181,40 @@ def _parse_json(body: bytes) -> Any:
|
||||
return None
|
||||
|
||||
|
||||
def _repository_facts(value: Any) -> dict[str, Any]:
|
||||
def _repository_facts(value: Any, context: dict[str, Any]) -> dict[str, Any]:
|
||||
if not isinstance(value, dict):
|
||||
return {"repository_shape": "unknown"}
|
||||
|
||||
if "repositoryId" in value:
|
||||
repository_id = str(value["repositoryId"])
|
||||
return {
|
||||
"repository_shape": "single-repository-info",
|
||||
"repository_ids": [value["repositoryId"]],
|
||||
"repository_ids": [repository_id],
|
||||
"selected_repository_id": repository_id,
|
||||
"cmis_version_supported": value.get("cmisVersionSupported"),
|
||||
"capabilities_present": isinstance(value.get("capabilities"), dict),
|
||||
"capability_flags": _capability_flags(value),
|
||||
"capability_posture": _capability_posture(value, context),
|
||||
}
|
||||
|
||||
repository_ids = []
|
||||
repositories: dict[str, dict[str, Any]] = {}
|
||||
for key, child in value.items():
|
||||
if isinstance(child, dict) and (
|
||||
"repositoryId" in child or "repositoryName" in child
|
||||
):
|
||||
repository_ids.append(str(child.get("repositoryId", key)))
|
||||
repositories[str(child.get("repositoryId", key))] = child
|
||||
|
||||
if repository_ids:
|
||||
if repositories:
|
||||
selected_repository_id = _selected_repository_id(repositories, context)
|
||||
selected_repository = repositories[selected_repository_id]
|
||||
return {
|
||||
"repository_shape": "repository-map",
|
||||
"repository_ids": repository_ids,
|
||||
"repository_ids": sorted(repositories),
|
||||
"selected_repository_id": selected_repository_id,
|
||||
"cmis_version_supported": selected_repository.get("cmisVersionSupported"),
|
||||
"capabilities_present": isinstance(selected_repository.get("capabilities"), dict),
|
||||
"capability_flags": _capability_flags(selected_repository),
|
||||
"capability_posture": _capability_posture(selected_repository, context),
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -181,6 +223,99 @@ def _repository_facts(value: Any) -> dict[str, Any]:
|
||||
}
|
||||
|
||||
|
||||
def _selected_repository_id(
|
||||
repositories: dict[str, dict[str, Any]],
|
||||
context: dict[str, Any],
|
||||
) -> str:
|
||||
configured = _opencmis_policy(context).get("repository_id")
|
||||
if isinstance(configured, str) and configured in repositories:
|
||||
return configured
|
||||
return sorted(repositories)[0]
|
||||
|
||||
|
||||
def _capability_flags(repository_info: dict[str, Any]) -> dict[str, Any]:
|
||||
capabilities = repository_info.get("capabilities", {})
|
||||
return dict(capabilities) if isinstance(capabilities, dict) else {}
|
||||
|
||||
|
||||
def _capability_posture(
|
||||
repository_info: dict[str, Any],
|
||||
context: dict[str, Any],
|
||||
) -> list[dict[str, Any]]:
|
||||
target = context["target_profile"]
|
||||
declared = set(target.get("declared_capabilities", []))
|
||||
known_gap_refs = {
|
||||
requirement_ref: gap["id"]
|
||||
for gap in target.get("known_gaps", [])
|
||||
for requirement_ref in gap.get("requirement_refs", [])
|
||||
}
|
||||
refs = sorted(declared | set(known_gap_refs))
|
||||
flags = _capability_flags(repository_info)
|
||||
posture = []
|
||||
for requirement_ref in refs:
|
||||
support = _requirement_support(requirement_ref, flags)
|
||||
if support is True:
|
||||
status = "supported"
|
||||
elif support is False and requirement_ref in known_gap_refs:
|
||||
status = "expected_gap"
|
||||
elif support is False:
|
||||
status = "unsupported"
|
||||
else:
|
||||
status = "unknown"
|
||||
posture.append(
|
||||
{
|
||||
"requirement_ref": requirement_ref,
|
||||
"status": status,
|
||||
"known_gap_ref": known_gap_refs.get(requirement_ref),
|
||||
"flag_refs": _flag_refs(requirement_ref),
|
||||
}
|
||||
)
|
||||
return posture
|
||||
|
||||
|
||||
def _requirement_support(requirement_ref: str, flags: dict[str, Any]) -> bool | None:
|
||||
if requirement_ref == "cmis.repository-info":
|
||||
return True
|
||||
flag_refs = _flag_refs(requirement_ref)
|
||||
if not flag_refs:
|
||||
return None
|
||||
values = [flags[key] for key in flag_refs if key in flags]
|
||||
if not values:
|
||||
return None
|
||||
return any(_flag_supports(value) for value in values)
|
||||
|
||||
|
||||
def _flag_refs(requirement_ref: str) -> list[str]:
|
||||
return {
|
||||
"cmis.query": ["capabilityQuery"],
|
||||
"cmis.acl": ["capabilityACL"],
|
||||
"cmis.navigation-services": [
|
||||
"capabilityGetDescendants",
|
||||
"capabilityGetFolderTree",
|
||||
],
|
||||
"cmis.relationships": ["capabilityJoin"],
|
||||
"cmis.change-log": ["capabilityChanges"],
|
||||
"cmis.versioning": [
|
||||
"capabilityVersionSpecificFiling",
|
||||
"capabilityPWCSearchable",
|
||||
"capabilityPWCUpdatable",
|
||||
],
|
||||
}.get(requirement_ref, [])
|
||||
|
||||
|
||||
def _flag_supports(value: Any) -> bool:
|
||||
if isinstance(value, bool):
|
||||
return value
|
||||
if isinstance(value, str):
|
||||
return value.lower() not in {"", "false", "none", "no"}
|
||||
return value is not None
|
||||
|
||||
|
||||
def _opencmis_policy(context: dict[str, Any]) -> dict[str, Any]:
|
||||
policy = context["assessment_profile"].get("runtime_policy", {}).get("opencmis_tck", {})
|
||||
return policy if isinstance(policy, dict) else {}
|
||||
|
||||
|
||||
def _write_response_artifacts(
|
||||
context: dict[str, Any],
|
||||
status_code: int,
|
||||
|
||||
146
src/open_cmis_tck/profile.py
Normal file
146
src/open_cmis_tck/profile.py
Normal file
@@ -0,0 +1,146 @@
|
||||
"""CMIS-specific profile diagnostics for guide-board target profiles."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
from urllib.parse import urlparse
|
||||
|
||||
|
||||
KNOWN_CMIS_REQUIREMENTS = {
|
||||
"cmis.repository-info",
|
||||
"cmis.type-definitions",
|
||||
"cmis.object-services",
|
||||
"cmis.content-streams",
|
||||
"cmis.navigation-services",
|
||||
"cmis.query",
|
||||
"cmis.relationships",
|
||||
"cmis.acl",
|
||||
"cmis.policies",
|
||||
"cmis.versioning",
|
||||
"cmis.change-log",
|
||||
"cmis.extensions",
|
||||
}
|
||||
|
||||
|
||||
def validate_cmis_profile_config(
|
||||
target_profile: dict[str, Any],
|
||||
assessment_profile: dict[str, Any] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""Return actionable CMIS diagnostics for guide-board profiles.
|
||||
|
||||
The generic guide-board target profile remains the persisted contract. This
|
||||
helper explains how the OpenCMIS extension interprets those generic fields.
|
||||
"""
|
||||
|
||||
diagnostics: list[dict[str, str]] = []
|
||||
browser_endpoints = [
|
||||
endpoint
|
||||
for endpoint in target_profile.get("endpoints", [])
|
||||
if endpoint.get("binding") == "cmis-browser"
|
||||
]
|
||||
|
||||
if target_profile.get("subject_type") != "cmis-browser-binding-endpoint":
|
||||
diagnostics.append(
|
||||
_diagnostic(
|
||||
"warning",
|
||||
"subject_type",
|
||||
"CMIS targets should use subject_type 'cmis-browser-binding-endpoint'.",
|
||||
)
|
||||
)
|
||||
|
||||
if not browser_endpoints:
|
||||
diagnostics.append(
|
||||
_diagnostic(
|
||||
"error",
|
||||
"endpoints",
|
||||
"Add one endpoint with binding 'cmis-browser' and the Browser Binding service document URL.",
|
||||
)
|
||||
)
|
||||
for index, endpoint in enumerate(browser_endpoints):
|
||||
parsed = urlparse(str(endpoint.get("url", "")))
|
||||
if parsed.scheme not in {"http", "https"} or not parsed.netloc:
|
||||
diagnostics.append(
|
||||
_diagnostic(
|
||||
"error",
|
||||
f"endpoints[{index}].url",
|
||||
"Use an absolute http(s) CMIS Browser Binding URL.",
|
||||
)
|
||||
)
|
||||
|
||||
declared = set(target_profile.get("declared_capabilities", []))
|
||||
unknown_declared = sorted(declared - KNOWN_CMIS_REQUIREMENTS)
|
||||
for requirement_ref in unknown_declared:
|
||||
diagnostics.append(
|
||||
_diagnostic(
|
||||
"warning",
|
||||
"declared_capabilities",
|
||||
f"Declared CMIS capability {requirement_ref!r} is not in the extension's known requirement list.",
|
||||
)
|
||||
)
|
||||
|
||||
known_gap_refs = {
|
||||
requirement_ref
|
||||
for gap in target_profile.get("known_gaps", [])
|
||||
for requirement_ref in gap.get("requirement_refs", [])
|
||||
}
|
||||
unexpected_gap_refs = sorted(known_gap_refs - KNOWN_CMIS_REQUIREMENTS)
|
||||
for requirement_ref in unexpected_gap_refs:
|
||||
diagnostics.append(
|
||||
_diagnostic(
|
||||
"warning",
|
||||
"known_gaps",
|
||||
f"Known gap {requirement_ref!r} is not in the extension's known requirement list.",
|
||||
)
|
||||
)
|
||||
|
||||
runtime_policy = (assessment_profile or {}).get("runtime_policy", {})
|
||||
opencmis_policy = runtime_policy.get("opencmis_tck", {})
|
||||
if opencmis_policy and not isinstance(opencmis_policy, dict):
|
||||
diagnostics.append(
|
||||
_diagnostic(
|
||||
"error",
|
||||
"runtime_policy.opencmis_tck",
|
||||
"OpenCMIS runtime policy must be an object when present.",
|
||||
)
|
||||
)
|
||||
opencmis_policy = {}
|
||||
|
||||
timeout = runtime_policy.get("timeout_seconds")
|
||||
if assessment_profile is not None and not isinstance(timeout, (int, float)):
|
||||
diagnostics.append(
|
||||
_diagnostic(
|
||||
"warning",
|
||||
"runtime_policy.timeout_seconds",
|
||||
"Set timeout_seconds to bound preflight and TCK execution.",
|
||||
)
|
||||
)
|
||||
|
||||
repository_id = None
|
||||
if isinstance(opencmis_policy, dict):
|
||||
repository_id = opencmis_policy.get("repository_id")
|
||||
if repository_id is not None and not isinstance(repository_id, str):
|
||||
diagnostics.append(
|
||||
_diagnostic(
|
||||
"error",
|
||||
"runtime_policy.opencmis_tck.repository_id",
|
||||
"repository_id must be a string when configured.",
|
||||
)
|
||||
)
|
||||
|
||||
status = "invalid" if any(item["severity"] == "error" for item in diagnostics) else "valid"
|
||||
return {
|
||||
"status": status,
|
||||
"diagnostics": diagnostics,
|
||||
"cmis_config": {
|
||||
"browser_binding_url": browser_endpoints[0]["url"] if browser_endpoints else None,
|
||||
"repository_id": repository_id,
|
||||
"auth_mode": "anonymous" if target_profile.get("credentials_ref") is None else "credentials_ref",
|
||||
"declared_capabilities": sorted(declared),
|
||||
"known_gap_refs": sorted(known_gap_refs),
|
||||
"timeout_seconds": timeout,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _diagnostic(severity: str, field: str, message: str) -> dict[str, str]:
|
||||
return {"severity": severity, "field": field, "message": message}
|
||||
Reference in New Issue
Block a user