phlo-clickstack 0.4.0__tar.gz → 0.15.1__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.
- {phlo_clickstack-0.4.0 → phlo_clickstack-0.15.1}/PKG-INFO +2 -2
- {phlo_clickstack-0.4.0 → phlo_clickstack-0.15.1}/pyproject.toml +2 -2
- {phlo_clickstack-0.4.0 → phlo_clickstack-0.15.1}/src/phlo_clickstack/authorization.py +8 -3
- {phlo_clickstack-0.4.0 → phlo_clickstack-0.15.1}/src/phlo_clickstack/cli.py +9 -42
- {phlo_clickstack-0.4.0 → phlo_clickstack-0.15.1}/src/phlo_clickstack/cli_plugin.py +7 -1
- {phlo_clickstack-0.4.0 → phlo_clickstack-0.15.1}/src/phlo_clickstack/observability_backend.py +12 -1
- phlo_clickstack-0.15.1/src/phlo_clickstack/plugin.py +23 -0
- {phlo_clickstack-0.4.0 → phlo_clickstack-0.15.1}/src/phlo_clickstack/resource_provider.py +10 -1
- {phlo_clickstack-0.4.0 → phlo_clickstack-0.15.1}/src/phlo_clickstack/service.yaml +1 -4
- {phlo_clickstack-0.4.0 → phlo_clickstack-0.15.1}/src/phlo_clickstack.egg-info/PKG-INFO +2 -2
- {phlo_clickstack-0.4.0 → phlo_clickstack-0.15.1}/src/phlo_clickstack.egg-info/requires.txt +1 -1
- {phlo_clickstack-0.4.0 → phlo_clickstack-0.15.1}/tests/test_authorization.py +37 -65
- {phlo_clickstack-0.4.0 → phlo_clickstack-0.15.1}/tests/test_clickstack_cli.py +8 -1
- {phlo_clickstack-0.4.0 → phlo_clickstack-0.15.1}/tests/test_clickstack_plugin.py +16 -1
- {phlo_clickstack-0.4.0 → phlo_clickstack-0.15.1}/tests/test_observability_backend.py +6 -1
- phlo_clickstack-0.4.0/src/phlo_clickstack/plugin.py +0 -15
- {phlo_clickstack-0.4.0 → phlo_clickstack-0.15.1}/README.md +0 -0
- {phlo_clickstack-0.4.0 → phlo_clickstack-0.15.1}/setup.cfg +0 -0
- {phlo_clickstack-0.4.0 → phlo_clickstack-0.15.1}/src/phlo_clickstack/__init__.py +0 -0
- {phlo_clickstack-0.4.0 → phlo_clickstack-0.15.1}/src/phlo_clickstack.egg-info/SOURCES.txt +0 -0
- {phlo_clickstack-0.4.0 → phlo_clickstack-0.15.1}/src/phlo_clickstack.egg-info/dependency_links.txt +0 -0
- {phlo_clickstack-0.4.0 → phlo_clickstack-0.15.1}/src/phlo_clickstack.egg-info/entry_points.txt +0 -0
- {phlo_clickstack-0.4.0 → phlo_clickstack-0.15.1}/src/phlo_clickstack.egg-info/top_level.txt +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: phlo-clickstack
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.15.1
|
|
4
4
|
Summary: clickstack service plugin for Phlo
|
|
5
5
|
Author-email: Phlo Team <team@phlo.dev>
|
|
6
6
|
License: MIT
|
|
7
7
|
Requires-Python: >=3.11
|
|
8
8
|
Description-Content-Type: text/plain
|
|
9
|
-
Requires-Dist: phlo
|
|
9
|
+
Requires-Dist: phlo<0.16,>=0.15.1
|
|
10
10
|
Requires-Dist: requests>=2.32.5
|
|
11
11
|
Provides-Extra: dev
|
|
12
12
|
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
@@ -7,13 +7,13 @@ requires = [
|
|
|
7
7
|
|
|
8
8
|
[project]
|
|
9
9
|
dependencies = [
|
|
10
|
-
"phlo>=0.1.
|
|
10
|
+
"phlo>=0.15.1,<0.16",
|
|
11
11
|
"requests>=2.32.5",
|
|
12
12
|
]
|
|
13
13
|
description = "clickstack service plugin for Phlo"
|
|
14
14
|
name = "phlo-clickstack"
|
|
15
15
|
requires-python = ">=3.11"
|
|
16
|
-
version = "0.
|
|
16
|
+
version = "0.15.1"
|
|
17
17
|
|
|
18
18
|
[[project.authors]]
|
|
19
19
|
email = "team@phlo.dev"
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Authorization table for the phlo-clickstack CLI surface.
|
|
2
|
+
|
|
3
|
+
Declares which commands mutate state and maps every command onto the resource
|
|
4
|
+
and action names evaluated by the shared CLI surface adapter.
|
|
5
|
+
"""
|
|
2
6
|
|
|
3
7
|
from __future__ import annotations
|
|
4
8
|
|
|
5
|
-
from phlo.cli.authorization import cli_surface_adapter_class
|
|
9
|
+
from phlo.cli.authorization import CliSurfaceAdapter, cli_surface_adapter_class
|
|
6
10
|
|
|
7
11
|
SURFACE_NAME = "phlo-clickstack"
|
|
8
12
|
FRAMEWORK_TYPE = "cli"
|
|
@@ -23,5 +27,6 @@ ClickStackSurfaceAdapter = cli_surface_adapter_class(
|
|
|
23
27
|
)
|
|
24
28
|
|
|
25
29
|
|
|
26
|
-
def get_adapter() ->
|
|
30
|
+
def get_adapter() -> CliSurfaceAdapter:
|
|
31
|
+
"""Return the shared ClickStackSurfaceAdapter instance for this surface."""
|
|
27
32
|
return ClickStackSurfaceAdapter.get_instance()
|
|
@@ -35,23 +35,10 @@ logger = get_logger(__name__)
|
|
|
35
35
|
def _read_query(*, query: str | None, file: Path | None) -> str:
|
|
36
36
|
"""Read and validate SQL query from inline argument or file.
|
|
37
37
|
|
|
38
|
-
Accepts either an inline SQL query string or a path to a SQL file
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
Args:
|
|
43
|
-
query: Inline SQL query string, or None if reading from file.
|
|
44
|
-
file: Path to SQL file, or None if using inline query.
|
|
45
|
-
|
|
46
|
-
Returns:
|
|
47
|
-
str: The SQL query text to execute.
|
|
48
|
-
|
|
49
|
-
Raises:
|
|
50
|
-
click.ClickException: If both query and file are provided.
|
|
51
|
-
click.ClickException: If file cannot be read.
|
|
52
|
-
click.ClickException: If file is empty or contains only whitespace.
|
|
53
|
-
click.ClickException: If neither query nor file is provided.
|
|
54
|
-
|
|
38
|
+
Accepts either an inline SQL query string or a path to a SQL file;
|
|
39
|
+
exactly one non-empty source must be provided. Raises ClickException
|
|
40
|
+
when both are given, the file is unreadable/empty, or neither is
|
|
41
|
+
provided.
|
|
55
42
|
"""
|
|
56
43
|
if query and file:
|
|
57
44
|
raise exclusive_options_error("an inline query", "--file")
|
|
@@ -71,15 +58,8 @@ def _read_query(*, query: str | None, file: Path | None) -> str:
|
|
|
71
58
|
def _ensure_phlo_dir() -> Path:
|
|
72
59
|
"""Locate and return the local .phlo directory.
|
|
73
60
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
Returns:
|
|
78
|
-
Path: Path to the .phlo directory.
|
|
79
|
-
|
|
80
|
-
Raises:
|
|
81
|
-
click.ClickException: If .phlo directory does not exist.
|
|
82
|
-
|
|
61
|
+
Required for Docker Compose project configuration; raises
|
|
62
|
+
ClickException when the directory does not exist.
|
|
83
63
|
"""
|
|
84
64
|
return ensure_compose_project()
|
|
85
65
|
|
|
@@ -113,22 +93,9 @@ def clickstack_query(
|
|
|
113
93
|
|
|
114
94
|
Runs a SQL query via clickhouse-client inside the ClickStack container.
|
|
115
95
|
Accepts SQL either as a command argument or from a file. Requires Docker
|
|
116
|
-
and a running phlo services stack with ClickStack enabled
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
query: SQL query string to execute.
|
|
120
|
-
query_file: Path to file containing SQL query.
|
|
121
|
-
output_format: ClickHouse output format (default: TabSeparatedRaw).
|
|
122
|
-
timeout_seconds: Query execution timeout in seconds.
|
|
123
|
-
|
|
124
|
-
Raises:
|
|
125
|
-
click.ClickException: If Docker is unavailable.
|
|
126
|
-
click.ClickException: If .phlo directory is missing.
|
|
127
|
-
click.ClickException: If both query and file options provided.
|
|
128
|
-
click.ClickException: If query file cannot be read.
|
|
129
|
-
click.ClickException: If query execution fails.
|
|
130
|
-
click.ClickException: If query times out.
|
|
131
|
-
|
|
96
|
+
and a running phlo services stack with ClickStack enabled; raises
|
|
97
|
+
ClickException when Docker is unavailable, the .phlo directory is
|
|
98
|
+
missing, inputs are invalid, execution fails, or the query times out.
|
|
132
99
|
"""
|
|
133
100
|
sql = _read_query(query=query, file=query_file)
|
|
134
101
|
if is_mutating_sql(sql):
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
"""Clickstack CLI plugin registration.
|
|
1
|
+
"""Clickstack CLI plugin registration.
|
|
2
|
+
|
|
3
|
+
Registers the clickstack command group with the plugin system via
|
|
4
|
+
cli_command_plugin_class; owns no logic beyond registration.
|
|
5
|
+
|
|
6
|
+
Loaded through the phlo plugin entry-point mechanism at startup rather than imported directly.
|
|
7
|
+
"""
|
|
2
8
|
|
|
3
9
|
from __future__ import annotations
|
|
4
10
|
|
{phlo_clickstack-0.4.0 → phlo_clickstack-0.15.1}/src/phlo_clickstack/observability_backend.py
RENAMED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
"""ClickStack-backed observability capability provider.
|
|
1
|
+
"""ClickStack-backed observability capability provider.
|
|
2
|
+
|
|
3
|
+
Span queries post SQL to ClickStack's HTTP endpoint and decode its
|
|
4
|
+
newline-delimited JSON reply into TraceSpans. The endpoint resolves from
|
|
5
|
+
CLICKSTACK_QUERY_URL, falling back to the in-container service address or
|
|
6
|
+
localhost depending on environment.
|
|
7
|
+
"""
|
|
2
8
|
|
|
3
9
|
from __future__ import annotations
|
|
4
10
|
|
|
@@ -27,9 +33,14 @@ class ClickStackObservabilityBackend(DefaultObservabilityBackend):
|
|
|
27
33
|
"""Observability backend with OTEL span queries backed by ClickStack."""
|
|
28
34
|
|
|
29
35
|
def run_trace_spans(self, run_id: str, limit: int = 500) -> list[TraceSpan]:
|
|
36
|
+
"""Return trace spans for a single run id, bounded by limit."""
|
|
30
37
|
return self.trace_spans(TraceSpanFilter(run_id=run_id, limit=limit))
|
|
31
38
|
|
|
32
39
|
def trace_spans(self, filters: TraceSpanFilter) -> list[TraceSpan]:
|
|
40
|
+
"""Post the span query to ClickStack and decode newline-delimited JSON into TraceSpans.
|
|
41
|
+
|
|
42
|
+
Raises requests.HTTPError when the query request fails.
|
|
43
|
+
"""
|
|
33
44
|
query_url = self._resolve_clickstack_query_url()
|
|
34
45
|
query = _build_trace_spans_query(filters)
|
|
35
46
|
response = requests.post(
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Clickstack service plugin registration.
|
|
2
|
+
|
|
3
|
+
Declares the ClickStack observability backend (logs, metrics, traces)
|
|
4
|
+
as a service plugin. The class object is created at import time via
|
|
5
|
+
service_plugin_class so plugin discovery can pick it up without
|
|
6
|
+
instantiation.
|
|
7
|
+
Loaded through the phlo plugin entry-point mechanism at startup rather than imported directly.
|
|
8
|
+
Registers the clickstack observability backend service through phlo.plugins.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from phlo.plugins import service_plugin_class
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
ClickStackServicePlugin = service_plugin_class(
|
|
17
|
+
"ClickStackServicePlugin",
|
|
18
|
+
name="clickstack",
|
|
19
|
+
version="0.1.0",
|
|
20
|
+
description="ClickStack all-in-one observability backend",
|
|
21
|
+
author="Phlo Team",
|
|
22
|
+
tags=["observability", "logs", "metrics", "traces"],
|
|
23
|
+
)
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
"""Resource provider for ClickStack observability capabilities.
|
|
1
|
+
"""Resource provider for ClickStack observability capabilities.
|
|
2
|
+
|
|
3
|
+
ClickStackResourceProvider registers under the "clickstack" name and reports
|
|
4
|
+
ClickStack as an observability backend; it declares no standalone resources.
|
|
5
|
+
Loaded through the phlo plugin entry-point mechanism at startup rather than
|
|
6
|
+
imported directly; declares ClickStack as an observability backend via phlo.plugins.
|
|
7
|
+
"""
|
|
2
8
|
|
|
3
9
|
from __future__ import annotations
|
|
4
10
|
|
|
@@ -12,6 +18,7 @@ class ClickStackResourceProvider(ResourceProviderPlugin):
|
|
|
12
18
|
|
|
13
19
|
@property
|
|
14
20
|
def metadata(self) -> PluginMetadata:
|
|
21
|
+
"""Return the ClickStack provider metadata."""
|
|
15
22
|
return PluginMetadata(
|
|
16
23
|
name="clickstack",
|
|
17
24
|
version="0.1.0",
|
|
@@ -20,7 +27,9 @@ class ClickStackResourceProvider(ResourceProviderPlugin):
|
|
|
20
27
|
)
|
|
21
28
|
|
|
22
29
|
def get_resources(self) -> list:
|
|
30
|
+
"""Report no standalone resources."""
|
|
23
31
|
return []
|
|
24
32
|
|
|
25
33
|
def get_observability_backends(self):
|
|
34
|
+
"""Return the ClickStack observability backend spec."""
|
|
26
35
|
return [build_clickstack_observability_spec()]
|
|
@@ -4,7 +4,7 @@ category: observability
|
|
|
4
4
|
default: false
|
|
5
5
|
profile: observability
|
|
6
6
|
|
|
7
|
-
image:
|
|
7
|
+
image: docker.io/hyperdx/hyperdx-all-in-one:2.31.0@sha256:b01cc48cb5aaf30d630865a88217c826ab86fb9828374201f6cd7c539d5beed1
|
|
8
8
|
|
|
9
9
|
compose:
|
|
10
10
|
restart: unless-stopped
|
|
@@ -32,9 +32,6 @@ compose:
|
|
|
32
32
|
retries: 10
|
|
33
33
|
|
|
34
34
|
env_vars:
|
|
35
|
-
CLICKSTACK_IMAGE:
|
|
36
|
-
default: "docker.hyperdx.io/hyperdx/hyperdx-all-in-one"
|
|
37
|
-
description: Official ClickStack all-in-one image reference
|
|
38
35
|
CLICKSTACK_PORT:
|
|
39
36
|
default: 18080
|
|
40
37
|
description: ClickStack UI port
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: phlo-clickstack
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.15.1
|
|
4
4
|
Summary: clickstack service plugin for Phlo
|
|
5
5
|
Author-email: Phlo Team <team@phlo.dev>
|
|
6
6
|
License: MIT
|
|
7
7
|
Requires-Python: >=3.11
|
|
8
8
|
Description-Content-Type: text/plain
|
|
9
|
-
Requires-Dist: phlo
|
|
9
|
+
Requires-Dist: phlo<0.16,>=0.15.1
|
|
10
10
|
Requires-Dist: requests>=2.32.5
|
|
11
11
|
Provides-Extra: dev
|
|
12
12
|
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
"""Tests for ClickStack authorization module.
|
|
1
|
+
"""Tests for ClickStack authorization module.
|
|
2
|
+
|
|
3
|
+
Package-specific command-table coverage plus the shared surface-adapter
|
|
4
|
+
contract from ``phlo_testing.authorization_surface``: reads skip enforcement,
|
|
5
|
+
unknown commands deny closed, mutation commands honor policy allow/deny, and
|
|
6
|
+
the shared ``CliPrincipalResolver`` environment fallbacks hold.
|
|
7
|
+
"""
|
|
2
8
|
|
|
3
9
|
from __future__ import annotations
|
|
4
10
|
|
|
@@ -8,6 +14,13 @@ from unittest.mock import patch
|
|
|
8
14
|
import pytest
|
|
9
15
|
|
|
10
16
|
from phlo.cli.authorization import CliPrincipalResolver
|
|
17
|
+
from phlo_testing.authorization_surface import (
|
|
18
|
+
assert_mutation_enforcement_allows_and_denies,
|
|
19
|
+
assert_read_commands_allow_without_enforcement,
|
|
20
|
+
assert_unknown_command_denied,
|
|
21
|
+
reset_surface_adapter_singleton,
|
|
22
|
+
run_cli_principal_resolver_contract,
|
|
23
|
+
)
|
|
11
24
|
from phlo_clickstack.authorization import (
|
|
12
25
|
COMMAND_ACTION_MAP,
|
|
13
26
|
COMMAND_RESOURCE_MAP,
|
|
@@ -21,32 +34,7 @@ pytestmark = pytest.mark.core_regression
|
|
|
21
34
|
|
|
22
35
|
|
|
23
36
|
class TestClickStackPrincipalResolver:
|
|
24
|
-
"""
|
|
25
|
-
|
|
26
|
-
def test_resolve_service_account(self):
|
|
27
|
-
"""PHLO_SERVICE_ACCOUNT creates service principal."""
|
|
28
|
-
env = {"PHLO_SERVICE_ACCOUNT": "ci-bot@phlo.svc"}
|
|
29
|
-
with patch.dict(os.environ, env, clear=True):
|
|
30
|
-
resolver = CliPrincipalResolver()
|
|
31
|
-
principal = resolver.resolve()
|
|
32
|
-
assert principal.subject == "ci-bot@phlo.svc"
|
|
33
|
-
assert principal.principal_type == "service"
|
|
34
|
-
assert "operators" in principal.groups
|
|
35
|
-
|
|
36
|
-
def test_resolve_human_principal(self):
|
|
37
|
-
"""PHLO_AUTH_SUBJECT creates human principal."""
|
|
38
|
-
env = {
|
|
39
|
-
"PHLO_AUTH_SUBJECT": "user@example.com",
|
|
40
|
-
"PHLO_AUTH_TYPE": "user",
|
|
41
|
-
"PHLO_AUTH_GROUPS": "admin,developers",
|
|
42
|
-
}
|
|
43
|
-
with patch.dict(os.environ, env, clear=True):
|
|
44
|
-
resolver = CliPrincipalResolver()
|
|
45
|
-
principal = resolver.resolve()
|
|
46
|
-
assert principal.subject == "user@example.com"
|
|
47
|
-
assert principal.principal_type == "user"
|
|
48
|
-
assert "admin" in principal.groups
|
|
49
|
-
assert "developers" in principal.groups
|
|
37
|
+
"""Extra principal-resolver edge case beyond the shared contract."""
|
|
50
38
|
|
|
51
39
|
def test_resolve_human_principal_empty_groups(self):
|
|
52
40
|
"""PHLO_AUTH_SUBJECT with no groups."""
|
|
@@ -60,34 +48,19 @@ class TestClickStackPrincipalResolver:
|
|
|
60
48
|
assert principal.subject == "user@example.com"
|
|
61
49
|
assert principal.groups == ()
|
|
62
50
|
|
|
63
|
-
def test_resolve_dev_mode_fallback(self):
|
|
64
|
-
"""PHLO_DEV_MODE creates admin fallback with warning."""
|
|
65
|
-
env = {"PHLO_DEV_MODE": "1"}
|
|
66
|
-
with patch.dict(os.environ, env, clear=True):
|
|
67
|
-
resolver = CliPrincipalResolver()
|
|
68
|
-
principal = resolver.resolve()
|
|
69
|
-
assert principal.subject == "local:root"
|
|
70
|
-
assert principal.principal_type == "user"
|
|
71
|
-
assert "admin" in principal.groups
|
|
72
51
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
with patch.dict(os.environ, env, clear=True):
|
|
77
|
-
resolver = CliPrincipalResolver()
|
|
78
|
-
principal = resolver.resolve()
|
|
79
|
-
assert principal.subject == "anonymous"
|
|
80
|
-
assert principal.principal_type == "user"
|
|
52
|
+
def test_cli_principal_resolver_contract():
|
|
53
|
+
"""The shared CLI principal resolver environment fallbacks hold."""
|
|
54
|
+
run_cli_principal_resolver_contract()
|
|
81
55
|
|
|
82
56
|
|
|
83
57
|
class TestClickStackSurfaceAdapter:
|
|
84
58
|
"""Tests for ClickStackSurfaceAdapter."""
|
|
85
59
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
ClickStackSurfaceAdapter._instance = None
|
|
60
|
+
@pytest.fixture(autouse=True)
|
|
61
|
+
def reset_singleton(self):
|
|
62
|
+
with reset_surface_adapter_singleton(ClickStackSurfaceAdapter):
|
|
63
|
+
yield
|
|
91
64
|
|
|
92
65
|
def test_surface_name(self):
|
|
93
66
|
adapter = ClickStackSurfaceAdapter()
|
|
@@ -131,25 +104,24 @@ class TestClickStackSurfaceAdapter:
|
|
|
131
104
|
class TestEnforcement:
|
|
132
105
|
"""Tests for ClickStack mutation enforcement."""
|
|
133
106
|
|
|
134
|
-
|
|
135
|
-
|
|
107
|
+
@pytest.fixture(autouse=True)
|
|
108
|
+
def reset_singleton(self):
|
|
109
|
+
with reset_surface_adapter_singleton(ClickStackSurfaceAdapter):
|
|
110
|
+
yield
|
|
136
111
|
|
|
137
|
-
def
|
|
138
|
-
|
|
112
|
+
def test_read_commands_allow_without_enforcement(self):
|
|
113
|
+
"""Read commands allow without touching the enforcement path."""
|
|
114
|
+
assert_read_commands_allow_without_enforcement(ClickStackSurfaceAdapter())
|
|
139
115
|
|
|
140
|
-
def
|
|
141
|
-
"""
|
|
142
|
-
|
|
143
|
-
for cmd in READ_COMMANDS:
|
|
144
|
-
result = adapter.check_command_authorization(cmd)
|
|
145
|
-
assert result.allowed, f"Read command {cmd} should be allowed"
|
|
116
|
+
def test_unknown_command_denied_closed(self):
|
|
117
|
+
"""Unknown commands are denied closed."""
|
|
118
|
+
assert_unknown_command_denied(ClickStackSurfaceAdapter(), "clickstack.unknown")
|
|
146
119
|
|
|
147
|
-
def
|
|
148
|
-
"""
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
assert result.reason_code == "unknown_command"
|
|
120
|
+
def test_clickstack_query_mutation_honors_policy_decision(self):
|
|
121
|
+
"""clickstack.query flows a policy allow through and blocks a policy deny."""
|
|
122
|
+
assert_mutation_enforcement_allows_and_denies(
|
|
123
|
+
ClickStackSurfaceAdapter(), "clickstack.query"
|
|
124
|
+
)
|
|
153
125
|
|
|
154
126
|
|
|
155
127
|
class TestMutationCommandLists:
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
"""Tests for ClickStack CLI commands.
|
|
1
|
+
"""Tests for ClickStack CLI commands.
|
|
2
|
+
|
|
3
|
+
Drives the query command through CliRunner with mocked subprocess calls to
|
|
4
|
+
verify SQL executes inside the ClickStack container via the project's
|
|
5
|
+
configured compose backend, that mutating statements pass through surface
|
|
6
|
+
mutation authorization, and that missing input or timeouts surface as CLI
|
|
7
|
+
errors.
|
|
8
|
+
"""
|
|
2
9
|
|
|
3
10
|
from __future__ import annotations
|
|
4
11
|
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
"""Tests for ClickStack service plugin.
|
|
1
|
+
"""Tests for the ClickStack service plugin.
|
|
2
|
+
|
|
3
|
+
Covers service definition metadata, pinned upstream images, and CLI rejection
|
|
4
|
+
of commands without an initialized .phlo directory.
|
|
5
|
+
"""
|
|
2
6
|
|
|
3
7
|
from click.testing import CliRunner
|
|
4
8
|
|
|
@@ -21,6 +25,17 @@ def test_clickstack_service_definition() -> None:
|
|
|
21
25
|
assert "./volumes/clickstack:/var/lib/clickhouse" not in defn["compose"]["volumes"]
|
|
22
26
|
|
|
23
27
|
|
|
28
|
+
def test_clickstack_uses_pinned_upstream_image() -> None:
|
|
29
|
+
definition = ClickStackServicePlugin().service_definition
|
|
30
|
+
|
|
31
|
+
assert definition["image"] == (
|
|
32
|
+
"docker.io/hyperdx/hyperdx-all-in-one:2.31.0@"
|
|
33
|
+
"sha256:b01cc48cb5aaf30d630865a88217c826ab86fb9828374201f6cd7c539d5beed1"
|
|
34
|
+
)
|
|
35
|
+
assert "build" not in definition
|
|
36
|
+
assert "CLICKSTACK_IMAGE" not in definition["env_vars"]
|
|
37
|
+
|
|
38
|
+
|
|
24
39
|
def test_clickstack_plugin_metadata() -> None:
|
|
25
40
|
"""Validate ClickStack plugin metadata."""
|
|
26
41
|
plugin = ClickStackServicePlugin()
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
"""Tests for ClickStack observability backend capability.
|
|
1
|
+
"""Tests for ClickStack observability backend capability.
|
|
2
|
+
|
|
3
|
+
Covers spec defaults, host-port versus in-container query URL selection,
|
|
4
|
+
trace span queries issued to the ClickStack HTTP API, and filter-aware query
|
|
5
|
+
construction.
|
|
6
|
+
"""
|
|
2
7
|
|
|
3
8
|
from __future__ import annotations
|
|
4
9
|
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
"""Clickstack service plugin registration."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
from phlo.plugins import service_plugin_class
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
ClickStackServicePlugin = service_plugin_class(
|
|
9
|
-
"ClickStackServicePlugin",
|
|
10
|
-
name="clickstack",
|
|
11
|
-
version="0.1.0",
|
|
12
|
-
description="ClickStack all-in-one observability backend",
|
|
13
|
-
author="Phlo Team",
|
|
14
|
-
tags=["observability", "logs", "metrics", "traces"],
|
|
15
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{phlo_clickstack-0.4.0 → phlo_clickstack-0.15.1}/src/phlo_clickstack.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{phlo_clickstack-0.4.0 → phlo_clickstack-0.15.1}/src/phlo_clickstack.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|