cloudfall 0.2.0__py3-none-any.whl
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.
- cloudfall/__init__.py +19 -0
- cloudfall/__main__.py +5 -0
- cloudfall/_bundled/schemas/v1/alert-rule.schema.json +63 -0
- cloudfall/_bundled/schemas/v1/application.schema.json +60 -0
- cloudfall/_bundled/schemas/v1/artifact.schema.json +71 -0
- cloudfall/_bundled/schemas/v1/backup-receipt.schema.json +58 -0
- cloudfall/_bundled/schemas/v1/common.schema.json +115 -0
- cloudfall/_bundled/schemas/v1/component.schema.json +234 -0
- cloudfall/_bundled/schemas/v1/deployment-receipt.schema.json +53 -0
- cloudfall/_bundled/schemas/v1/domain.schema.json +208 -0
- cloudfall/_bundled/schemas/v1/environment-receipt.schema.json +55 -0
- cloudfall/_bundled/schemas/v1/logging-stack.schema.json +473 -0
- cloudfall/_bundled/schemas/v1/observed-domain.schema.json +158 -0
- cloudfall/_bundled/schemas/v1/observed-server.schema.json +627 -0
- cloudfall/_bundled/schemas/v1/operator-policy.schema.json +97 -0
- cloudfall/_bundled/schemas/v1/operator-proposal.schema.json +253 -0
- cloudfall/_bundled/schemas/v1/release-receipt.schema.json +66 -0
- cloudfall/_bundled/schemas/v1/server-type.schema.json +289 -0
- cloudfall/_bundled/schemas/v1/server.schema.json +146 -0
- cloudfall/_bundled/schemas/v1/service.schema.json +222 -0
- cloudfall/_bundled/schemas/v1/ssh-public-key.schema.json +55 -0
- cloudfall/agent_tools.py +868 -0
- cloudfall/arguments.py +92 -0
- cloudfall/audit.py +905 -0
- cloudfall/authoring.py +341 -0
- cloudfall/cli.py +1748 -0
- cloudfall/commands.py +257 -0
- cloudfall/cutover.py +370 -0
- cloudfall/dashboard.py +407 -0
- cloudfall/dashboard_server.py +201 -0
- cloudfall/domain.py +1157 -0
- cloudfall/importer.py +906 -0
- cloudfall/inventory.py +2116 -0
- cloudfall/lifecycle.py +874 -0
- cloudfall/mcp_server.py +704 -0
- cloudfall/migrate.py +730 -0
- cloudfall/observation.py +143 -0
- cloudfall/operations.py +1228 -0
- cloudfall/operator.py +1099 -0
- cloudfall/project.py +841 -0
- cloudfall/py.typed +0 -0
- cloudfall/render_api.py +338 -0
- cloudfall/resources.py +67 -0
- cloudfall/secrets.py +262 -0
- cloudfall/service_evidence.py +659 -0
- cloudfall/validation.py +1340 -0
- cloudfall-0.2.0.dist-info/METADATA +408 -0
- cloudfall-0.2.0.dist-info/RECORD +165 -0
- cloudfall-0.2.0.dist-info/WHEEL +4 -0
- cloudfall-0.2.0.dist-info/entry_points.txt +4 -0
- cloudfall-0.2.0.dist-info/licenses/LICENSE +661 -0
- cloudfall_engine/__init__.py +5 -0
- cloudfall_engine/__main__.py +5 -0
- cloudfall_engine/_bundled/ansible/ansible.cfg +7 -0
- cloudfall_engine/_bundled/ansible/playbooks/backup.yml +86 -0
- cloudfall_engine/_bundled/ansible/playbooks/baseline.yml +35 -0
- cloudfall_engine/_bundled/ansible/playbooks/bootstrap.yml +24 -0
- cloudfall_engine/_bundled/ansible/playbooks/data.yml +28 -0
- cloudfall_engine/_bundled/ansible/playbooks/deploy.yml +35 -0
- cloudfall_engine/_bundled/ansible/playbooks/domains.yml +21 -0
- cloudfall_engine/_bundled/ansible/playbooks/health.yml +31 -0
- cloudfall_engine/_bundled/ansible/playbooks/inspect.yml +15 -0
- cloudfall_engine/_bundled/ansible/playbooks/logging.yml +35 -0
- cloudfall_engine/_bundled/ansible/playbooks/restart.yml +31 -0
- cloudfall_engine/_bundled/ansible/playbooks/rollback.yml +33 -0
- cloudfall_engine/_bundled/ansible/playbooks/services.yml +37 -0
- cloudfall_engine/_bundled/ansible/playbooks/time.yml +9 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_access/defaults/main.yml +2 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_access/handlers/main.yml +5 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_access/meta/argument_specs.yml +34 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_access/meta/main.yml +13 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_access/tasks/main.yml +59 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_bootstrap/defaults/main.yml +11 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_bootstrap/meta/argument_specs.yml +52 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_bootstrap/meta/main.yml +13 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_bootstrap/tasks/main.yml +99 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_data_migration/defaults/main.yml +15 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_data_migration/meta/argument_specs.yml +36 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_data_migration/meta/main.yml +13 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_data_migration/tasks/main.yml +201 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_deploy/defaults/main.yml +10 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_deploy/meta/argument_specs.yml +125 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_deploy/meta/main.yml +13 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_deploy/tasks/health.yml +3 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_deploy/tasks/health_gate.yml +37 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_deploy/tasks/main.yml +285 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_deploy/tasks/restart.yml +17 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_deploy/tasks/rollback.yml +52 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_deploy/templates/component.service.j2 +24 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_firewall/defaults/main.yml +2 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_firewall/handlers/main.yml +5 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_firewall/meta/argument_specs.yml +33 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_firewall/meta/main.yml +13 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_firewall/tasks/main.yml +51 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_firewall/templates/nftables.conf.j2 +31 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_inspect/defaults/main.yml +6 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_inspect/meta/argument_specs.yml +24 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_inspect/meta/main.yml +13 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_inspect/tasks/main.yml +643 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/defaults/main.yml +6 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/handlers/main.yml +29 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/meta/argument_specs.yml +227 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/meta/main.yml +11 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/tasks/main.yml +487 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/templates/alertmanager-defaults.j2 +2 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/templates/alertmanager.yaml.j2 +33 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/templates/grafana.ini.j2 +20 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/templates/loki-datasource.yml.j2 +11 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/templates/loki-systemd-override.conf.j2 +3 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/templates/loki.yaml.j2 +49 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/templates/nginx-loki-gateway.conf.j2 +45 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/templates/prometheus-datasource.yml.j2 +11 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/templates/prometheus-defaults.j2 +2 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/templates/prometheus-rules.yaml.j2 +20 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_backend/templates/prometheus.yaml.j2 +24 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_collector/defaults/main.yml +7 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_collector/handlers/main.yml +6 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_collector/meta/argument_specs.yml +122 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_collector/meta/main.yml +11 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_collector/tasks/main.yml +224 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_collector/templates/alloy-systemd-override.conf.j2 +3 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_logging_collector/templates/config.alloy.j2 +127 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_nginx_site/defaults/main.yml +4 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_nginx_site/handlers/main.yml +5 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_nginx_site/meta/argument_specs.yml +69 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_nginx_site/meta/main.yml +13 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_nginx_site/tasks/main.yml +212 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_nginx_site/templates/domain-site.conf.j2 +54 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_postgresql/defaults/main.yml +6 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_postgresql/handlers/main.yml +9 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_postgresql/meta/argument_specs.yml +91 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_postgresql/meta/main.yml +13 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_postgresql/tasks/main.yml +295 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_postgresql/templates/backup.service.j2 +11 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_postgresql/templates/backup.sh.j2 +17 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_postgresql/templates/backup.timer.j2 +10 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_postgresql/templates/cloudfall.conf.j2 +3 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_postgresql/templates/restore-check.service.j2 +11 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_postgresql/templates/restore-check.sh.j2 +27 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_postgresql/templates/restore-check.timer.j2 +10 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_redis/defaults/main.yml +2 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_redis/handlers/main.yml +6 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_redis/meta/argument_specs.yml +68 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_redis/meta/main.yml +13 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_redis/tasks/main.yml +148 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_redis/templates/backup.service.j2 +11 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_redis/templates/backup.sh.j2 +14 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_redis/templates/backup.timer.j2 +10 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_redis/templates/cloudfall.conf.j2 +6 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_redis/templates/restore-check.service.j2 +11 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_redis/templates/restore-check.sh.j2 +15 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_redis/templates/restore-check.timer.j2 +10 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_time/defaults/main.yml +2 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_time/meta/argument_specs.yml +10 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_time/meta/main.yml +13 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_time/tasks/main.yml +119 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_unattended_upgrades/defaults/main.yml +3 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_unattended_upgrades/meta/argument_specs.yml +8 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_unattended_upgrades/meta/main.yml +13 -0
- cloudfall_engine/_bundled/ansible/roles/cloudfall_unattended_upgrades/tasks/main.yml +37 -0
- cloudfall_engine/ansible_inventory.py +253 -0
- cloudfall_engine/artifact.py +258 -0
- cloudfall_engine/cli.py +273 -0
- cloudfall_engine/playbook.py +175 -0
- cloudfall_engine/py.typed +0 -0
cloudfall/mcp_server.py
ADDED
|
@@ -0,0 +1,704 @@
|
|
|
1
|
+
"""MCP server exposing the Cloudfall agent toolset over stdio.
|
|
2
|
+
|
|
3
|
+
Requires the ``cloudfall[mcp]`` extra. Read-only evidence tools carry a
|
|
4
|
+
read-only annotation; anything that changes servers is annotated
|
|
5
|
+
destructive and demands the toolset's explicit confirmation handshake.
|
|
6
|
+
The fleet-declaring tools (``add_ssh_key``, ``add_server_type``,
|
|
7
|
+
``add_server``) write resources into the project and are neither: they
|
|
8
|
+
never touch a server and never overwrite an existing resource.
|
|
9
|
+
|
|
10
|
+
``cloudfall init`` is deliberately CLI-only. The server is started inside
|
|
11
|
+
a project (``--project``, ``CLOUDFALL_PROJECT``, or the current directory)
|
|
12
|
+
and refuses to start outside one, so by the time an agent can call a tool
|
|
13
|
+
the project already exists; a tool that lays out a new project elsewhere
|
|
14
|
+
would escape the directory every other tool is confined to.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import json
|
|
20
|
+
import os
|
|
21
|
+
import sys
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
from typing import TYPE_CHECKING
|
|
24
|
+
|
|
25
|
+
from mcp.server.mcpserver import MCPServer
|
|
26
|
+
from mcp.types import ToolAnnotations
|
|
27
|
+
|
|
28
|
+
from cloudfall.agent_tools import AgentConfig, AgentToolset
|
|
29
|
+
from cloudfall.arguments import (
|
|
30
|
+
StrictArgumentParser,
|
|
31
|
+
parse_arguments,
|
|
32
|
+
project_path_argument,
|
|
33
|
+
)
|
|
34
|
+
from cloudfall.project import (
|
|
35
|
+
PROJECT_DIRECTORY_VARIABLE,
|
|
36
|
+
ProjectError,
|
|
37
|
+
project_context,
|
|
38
|
+
)
|
|
39
|
+
from cloudfall.resources import default_engine_directory, default_schema_directory
|
|
40
|
+
|
|
41
|
+
if TYPE_CHECKING:
|
|
42
|
+
import argparse
|
|
43
|
+
from collections.abc import Callable, Sequence
|
|
44
|
+
|
|
45
|
+
_Registration = tuple[Callable[..., str], str, str, ToolAnnotations | None]
|
|
46
|
+
|
|
47
|
+
_INSTRUCTIONS = """\
|
|
48
|
+
Cloudfall manages declarative infrastructure state for dedicated Debian
|
|
49
|
+
servers. Read-only tools validate state and derive evidence; destructive
|
|
50
|
+
tools change servers and require calling twice: the first call returns a
|
|
51
|
+
confirmation-required preview, the second call with confirm=true executes.
|
|
52
|
+
Every mutation writes receipts; nothing reports success it cannot prove.
|
|
53
|
+
The add_ssh_key, add_server_type, and add_server tools declare the fleet:
|
|
54
|
+
they write schema-validated resource files into the project (never onto a
|
|
55
|
+
server), re-validate the whole project afterwards, and remove what they
|
|
56
|
+
wrote when that validation fails. They never overwrite an existing
|
|
57
|
+
resource. The project itself is laid out beforehand with `cloudfall init`
|
|
58
|
+
on the CLI; this server always runs inside an existing project.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def create_server(config: AgentConfig) -> MCPServer:
|
|
63
|
+
"""Create the MCP server and register every agent tool."""
|
|
64
|
+
server = MCPServer(name="cloudfall", instructions=_INSTRUCTIONS)
|
|
65
|
+
toolset = AgentToolset(config)
|
|
66
|
+
registrations = (
|
|
67
|
+
*_evidence_registrations(toolset),
|
|
68
|
+
*_authoring_registrations(toolset),
|
|
69
|
+
*_build_registrations(toolset),
|
|
70
|
+
*_mutation_registrations(toolset),
|
|
71
|
+
*_backup_registrations(toolset),
|
|
72
|
+
*_operator_registrations(toolset),
|
|
73
|
+
)
|
|
74
|
+
for handler, name, description, tool_annotations in registrations:
|
|
75
|
+
server.add_tool(
|
|
76
|
+
handler,
|
|
77
|
+
name=name,
|
|
78
|
+
description=description,
|
|
79
|
+
annotations=tool_annotations,
|
|
80
|
+
)
|
|
81
|
+
return server
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _evidence_registrations(
|
|
85
|
+
toolset: AgentToolset,
|
|
86
|
+
) -> tuple[_Registration, ...]:
|
|
87
|
+
read_only = ToolAnnotations(read_only_hint=True)
|
|
88
|
+
|
|
89
|
+
def validate_config() -> str:
|
|
90
|
+
return _dump(toolset.validate())
|
|
91
|
+
|
|
92
|
+
def show_inventory() -> str:
|
|
93
|
+
return _dump(toolset.inventory())
|
|
94
|
+
|
|
95
|
+
def audit_servers() -> str:
|
|
96
|
+
return _dump(toolset.audit())
|
|
97
|
+
|
|
98
|
+
def services_status() -> str:
|
|
99
|
+
return _dump(toolset.services_status())
|
|
100
|
+
|
|
101
|
+
def component_health(component: str) -> str:
|
|
102
|
+
return _dump(toolset.component_health(component))
|
|
103
|
+
|
|
104
|
+
def inspect_servers() -> str:
|
|
105
|
+
return _dump(toolset.inspect_servers())
|
|
106
|
+
|
|
107
|
+
def inspect_services() -> str:
|
|
108
|
+
return _dump(toolset.inspect_services())
|
|
109
|
+
|
|
110
|
+
return (
|
|
111
|
+
(
|
|
112
|
+
validate_config,
|
|
113
|
+
"validate_config",
|
|
114
|
+
"Validate declared config and resource references",
|
|
115
|
+
read_only,
|
|
116
|
+
),
|
|
117
|
+
(
|
|
118
|
+
show_inventory,
|
|
119
|
+
"show_inventory",
|
|
120
|
+
"Return the non-secret typed platform inventory",
|
|
121
|
+
read_only,
|
|
122
|
+
),
|
|
123
|
+
(
|
|
124
|
+
audit_servers,
|
|
125
|
+
"audit_servers",
|
|
126
|
+
"Compare desired state with collected server evidence",
|
|
127
|
+
read_only,
|
|
128
|
+
),
|
|
129
|
+
(
|
|
130
|
+
services_status,
|
|
131
|
+
"services_status",
|
|
132
|
+
"Derive the evidence-based public service lifecycle",
|
|
133
|
+
read_only,
|
|
134
|
+
),
|
|
135
|
+
(
|
|
136
|
+
component_health,
|
|
137
|
+
"component_health",
|
|
138
|
+
"Probe one component's declared health check on its servers",
|
|
139
|
+
read_only,
|
|
140
|
+
),
|
|
141
|
+
(
|
|
142
|
+
inspect_servers,
|
|
143
|
+
"inspect_servers",
|
|
144
|
+
"Collect read-only server evidence snapshots over SSH",
|
|
145
|
+
read_only,
|
|
146
|
+
),
|
|
147
|
+
(
|
|
148
|
+
inspect_services,
|
|
149
|
+
"inspect_services",
|
|
150
|
+
"Collect DNS, TLS, origin, and public route evidence",
|
|
151
|
+
read_only,
|
|
152
|
+
),
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def _authoring_registrations(
|
|
157
|
+
toolset: AgentToolset,
|
|
158
|
+
) -> tuple[_Registration, ...]:
|
|
159
|
+
writes_project = ToolAnnotations(
|
|
160
|
+
read_only_hint=False, destructive_hint=False, idempotent_hint=False
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
def add_ssh_key(
|
|
164
|
+
key_file: str,
|
|
165
|
+
owner: str,
|
|
166
|
+
id: str | None = None, # noqa: A002 - mirrors `cloudfall add --id`.
|
|
167
|
+
environment: str = "production",
|
|
168
|
+
description: str | None = None,
|
|
169
|
+
) -> str:
|
|
170
|
+
return _dump(
|
|
171
|
+
toolset.add_ssh_key(key_file, owner, id, environment, description)
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
def add_server_type(
|
|
175
|
+
id: str, # noqa: A002 - mirrors the `cloudfall add server-type` id.
|
|
176
|
+
description: str | None = None,
|
|
177
|
+
) -> str:
|
|
178
|
+
return _dump(toolset.add_server_type(id, description))
|
|
179
|
+
|
|
180
|
+
def add_server( # noqa: PLR0913 - boundary signature mirrors the CLI.
|
|
181
|
+
id: str, # noqa: A002 - mirrors the `cloudfall add server` id.
|
|
182
|
+
address: str,
|
|
183
|
+
type: str = "debian-application", # noqa: A002 - mirrors `--type`.
|
|
184
|
+
environment: str = "production",
|
|
185
|
+
hostname: str | None = None,
|
|
186
|
+
ssh_user: str = "root",
|
|
187
|
+
ssh_port: int = 22,
|
|
188
|
+
description: str | None = None,
|
|
189
|
+
) -> str:
|
|
190
|
+
return _dump(
|
|
191
|
+
toolset.add_server(
|
|
192
|
+
id,
|
|
193
|
+
address,
|
|
194
|
+
type,
|
|
195
|
+
environment,
|
|
196
|
+
hostname,
|
|
197
|
+
ssh_user,
|
|
198
|
+
ssh_port,
|
|
199
|
+
description,
|
|
200
|
+
)
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
return (
|
|
204
|
+
(
|
|
205
|
+
add_ssh_key,
|
|
206
|
+
"add_ssh_key",
|
|
207
|
+
"Declare an SshPublicKey resource read from a controller-side "
|
|
208
|
+
"public key file (e.g. ~/.ssh/id_ed25519.pub); writes into the "
|
|
209
|
+
"project and re-validates it, never overwrites",
|
|
210
|
+
writes_project,
|
|
211
|
+
),
|
|
212
|
+
(
|
|
213
|
+
add_server_type,
|
|
214
|
+
"add_server_type",
|
|
215
|
+
"Declare a ServerType resource from the bundled Debian 13 "
|
|
216
|
+
"baseline (no software RAID, default-deny firewall with "
|
|
217
|
+
"22/80/443); writes into the project and re-validates it, "
|
|
218
|
+
"never overwrites",
|
|
219
|
+
writes_project,
|
|
220
|
+
),
|
|
221
|
+
(
|
|
222
|
+
add_server,
|
|
223
|
+
"add_server",
|
|
224
|
+
"Declare a Server resource reachable at an address, creating "
|
|
225
|
+
"its baseline ServerType when the project lacks it; writes "
|
|
226
|
+
"into the project and re-validates it, never overwrites",
|
|
227
|
+
writes_project,
|
|
228
|
+
),
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def _build_registrations(toolset: AgentToolset) -> tuple[_Registration, ...]:
|
|
233
|
+
def import_render(
|
|
234
|
+
blueprint: str,
|
|
235
|
+
application: str,
|
|
236
|
+
server_id: str,
|
|
237
|
+
output_directory: str = "tmp/import/config",
|
|
238
|
+
environment_directory: str = "tmp/import/env",
|
|
239
|
+
) -> str:
|
|
240
|
+
return _dump(
|
|
241
|
+
toolset.import_render(
|
|
242
|
+
blueprint,
|
|
243
|
+
application,
|
|
244
|
+
server_id,
|
|
245
|
+
output_directory,
|
|
246
|
+
environment_directory,
|
|
247
|
+
)
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
def import_render_api(
|
|
251
|
+
api_key_file: str,
|
|
252
|
+
application: str,
|
|
253
|
+
server_id: str,
|
|
254
|
+
output_directory: str = "tmp/import/config",
|
|
255
|
+
environment_directory: str = "tmp/import/env",
|
|
256
|
+
) -> str:
|
|
257
|
+
return _dump(
|
|
258
|
+
toolset.import_render_api(
|
|
259
|
+
api_key_file,
|
|
260
|
+
application,
|
|
261
|
+
server_id,
|
|
262
|
+
output_directory,
|
|
263
|
+
environment_directory,
|
|
264
|
+
)
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
def render_secrets(component: str) -> str:
|
|
268
|
+
return _dump(toolset.render_secrets(component))
|
|
269
|
+
|
|
270
|
+
def build_artifact(component: str, git_ref: str) -> str:
|
|
271
|
+
return _dump(toolset.build_artifact(component, git_ref))
|
|
272
|
+
|
|
273
|
+
return (
|
|
274
|
+
(
|
|
275
|
+
import_render,
|
|
276
|
+
"import_render",
|
|
277
|
+
"Map a render.yaml blueprint onto Cloudfall config fragments "
|
|
278
|
+
"with a structured gap report",
|
|
279
|
+
None,
|
|
280
|
+
),
|
|
281
|
+
(
|
|
282
|
+
import_render_api,
|
|
283
|
+
"import_render_api",
|
|
284
|
+
"Map a live Render workspace onto Cloudfall config fragments "
|
|
285
|
+
"through the Render API; the api_key_file is a controller-side "
|
|
286
|
+
"file containing only the API key",
|
|
287
|
+
None,
|
|
288
|
+
),
|
|
289
|
+
(
|
|
290
|
+
render_secrets,
|
|
291
|
+
"render_secrets",
|
|
292
|
+
"Resolve a component's declared secret references from the "
|
|
293
|
+
"sops-encrypted secrets directory into its 0600 environment "
|
|
294
|
+
"file; the envelope carries key names and a hash, never values",
|
|
295
|
+
None,
|
|
296
|
+
),
|
|
297
|
+
(
|
|
298
|
+
build_artifact,
|
|
299
|
+
"build_artifact",
|
|
300
|
+
"Clone a component repository at a git ref and package a "
|
|
301
|
+
"hashed release artifact",
|
|
302
|
+
None,
|
|
303
|
+
),
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def _mutation_registrations(
|
|
308
|
+
toolset: AgentToolset,
|
|
309
|
+
) -> tuple[_Registration, ...]:
|
|
310
|
+
destructive = ToolAnnotations(read_only_hint=False, destructive_hint=True)
|
|
311
|
+
|
|
312
|
+
def deploy_component(
|
|
313
|
+
component: str,
|
|
314
|
+
release: str,
|
|
315
|
+
environment_file: str | None = None,
|
|
316
|
+
confirm: bool = False, # noqa: FBT001, FBT002 - explicit agent gate.
|
|
317
|
+
) -> str:
|
|
318
|
+
return _dump(
|
|
319
|
+
toolset.deploy_component(
|
|
320
|
+
component, release, environment_file, confirm=confirm
|
|
321
|
+
)
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
def rollback_component(
|
|
325
|
+
component: str,
|
|
326
|
+
release: str,
|
|
327
|
+
confirm: bool = False, # noqa: FBT001, FBT002 - explicit agent gate.
|
|
328
|
+
) -> str:
|
|
329
|
+
return _dump(toolset.rollback_component(component, release, confirm=confirm))
|
|
330
|
+
|
|
331
|
+
def restart_component(
|
|
332
|
+
component: str,
|
|
333
|
+
confirm: bool = False, # noqa: FBT001, FBT002 - explicit agent gate.
|
|
334
|
+
) -> str:
|
|
335
|
+
return _dump(toolset.restart_component(component, confirm=confirm))
|
|
336
|
+
|
|
337
|
+
def migrate_database(
|
|
338
|
+
service: str,
|
|
339
|
+
database: str,
|
|
340
|
+
source_url_file: str,
|
|
341
|
+
confirm: bool = False, # noqa: FBT001, FBT002 - explicit agent gate.
|
|
342
|
+
) -> str:
|
|
343
|
+
return _dump(
|
|
344
|
+
toolset.migrate_database(
|
|
345
|
+
service, database, source_url_file, confirm=confirm
|
|
346
|
+
)
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
def converge_baseline(
|
|
350
|
+
confirm: bool = False, # noqa: FBT001, FBT002 - explicit agent gate.
|
|
351
|
+
) -> str:
|
|
352
|
+
return _dump(toolset.converge_baseline(confirm=confirm))
|
|
353
|
+
|
|
354
|
+
def converge_services(
|
|
355
|
+
confirm: bool = False, # noqa: FBT001, FBT002 - explicit agent gate.
|
|
356
|
+
) -> str:
|
|
357
|
+
return _dump(toolset.converge_services(confirm=confirm))
|
|
358
|
+
|
|
359
|
+
def converge_domains(
|
|
360
|
+
issue_certificates: bool = False, # noqa: FBT001, FBT002 - explicit.
|
|
361
|
+
confirm: bool = False, # noqa: FBT001, FBT002 - explicit agent gate.
|
|
362
|
+
) -> str:
|
|
363
|
+
return _dump(
|
|
364
|
+
toolset.converge_domains(
|
|
365
|
+
issue_certificates=issue_certificates, confirm=confirm
|
|
366
|
+
)
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
def migrate( # noqa: PLR0913 - boundary signature mirrors the toolset.
|
|
370
|
+
builds: dict[str, str] | None = None,
|
|
371
|
+
releases: dict[str, str] | None = None,
|
|
372
|
+
environment_files: dict[str, str] | None = None,
|
|
373
|
+
data_migrations: dict[str, str] | None = None,
|
|
374
|
+
plan_file: str = "tmp/migrate/plan.json",
|
|
375
|
+
restart_plan: bool = False, # noqa: FBT001, FBT002 - explicit gate.
|
|
376
|
+
confirm: bool = False, # noqa: FBT001, FBT002 - explicit agent gate.
|
|
377
|
+
) -> str:
|
|
378
|
+
return _dump(
|
|
379
|
+
toolset.migrate(
|
|
380
|
+
builds,
|
|
381
|
+
releases,
|
|
382
|
+
environment_files,
|
|
383
|
+
data_migrations,
|
|
384
|
+
plan_file,
|
|
385
|
+
restart_plan=restart_plan,
|
|
386
|
+
confirm=confirm,
|
|
387
|
+
)
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
return (
|
|
391
|
+
(
|
|
392
|
+
deploy_component,
|
|
393
|
+
"deploy_component",
|
|
394
|
+
"Deploy one built release with digest verification, a health "
|
|
395
|
+
"gate, and automatic rollback; requires confirm=true",
|
|
396
|
+
destructive,
|
|
397
|
+
),
|
|
398
|
+
(
|
|
399
|
+
rollback_component,
|
|
400
|
+
"rollback_component",
|
|
401
|
+
"Activate an already-retained release behind the health gate; "
|
|
402
|
+
"requires confirm=true",
|
|
403
|
+
destructive,
|
|
404
|
+
),
|
|
405
|
+
(
|
|
406
|
+
restart_component,
|
|
407
|
+
"restart_component",
|
|
408
|
+
"Restart one component behind its health check; requires confirm=true",
|
|
409
|
+
destructive,
|
|
410
|
+
),
|
|
411
|
+
(
|
|
412
|
+
migrate_database,
|
|
413
|
+
"migrate_database",
|
|
414
|
+
"Dump an external PostgreSQL database and restore it into a "
|
|
415
|
+
"declared service with per-table row-count verification; the "
|
|
416
|
+
"source_url_file is a controller-side file containing only the "
|
|
417
|
+
"connection URL; requires confirm=true",
|
|
418
|
+
destructive,
|
|
419
|
+
),
|
|
420
|
+
(
|
|
421
|
+
converge_baseline,
|
|
422
|
+
"converge_baseline",
|
|
423
|
+
"Converge every server to the managed baseline; requires confirm=true",
|
|
424
|
+
destructive,
|
|
425
|
+
),
|
|
426
|
+
(
|
|
427
|
+
converge_services,
|
|
428
|
+
"converge_services",
|
|
429
|
+
"Converge every declared infrastructure service; requires confirm=true",
|
|
430
|
+
destructive,
|
|
431
|
+
),
|
|
432
|
+
(
|
|
433
|
+
converge_domains,
|
|
434
|
+
"converge_domains",
|
|
435
|
+
"Converge every declared public domain route; requires confirm=true",
|
|
436
|
+
destructive,
|
|
437
|
+
),
|
|
438
|
+
(
|
|
439
|
+
migrate,
|
|
440
|
+
"migrate",
|
|
441
|
+
"Preview (without confirm) or execute (confirm=true) the "
|
|
442
|
+
"resumable end-to-end migration plan: baseline, services, "
|
|
443
|
+
"builds, deployments, routes, DNS verification, TLS, and a "
|
|
444
|
+
"final compliance-proving evidence pass",
|
|
445
|
+
destructive,
|
|
446
|
+
),
|
|
447
|
+
)
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
def _backup_registrations(
|
|
451
|
+
toolset: AgentToolset,
|
|
452
|
+
) -> tuple[_Registration, ...]:
|
|
453
|
+
destructive = ToolAnnotations(read_only_hint=False, destructive_hint=True)
|
|
454
|
+
|
|
455
|
+
def backup_service(
|
|
456
|
+
service: str,
|
|
457
|
+
confirm: bool = False, # noqa: FBT001, FBT002 - explicit agent gate.
|
|
458
|
+
) -> str:
|
|
459
|
+
return _dump(toolset.backup_service(service, confirm=confirm))
|
|
460
|
+
|
|
461
|
+
def verify_backup(
|
|
462
|
+
service: str,
|
|
463
|
+
confirm: bool = False, # noqa: FBT001, FBT002 - explicit agent gate.
|
|
464
|
+
) -> str:
|
|
465
|
+
return _dump(toolset.verify_backup(service, confirm=confirm))
|
|
466
|
+
|
|
467
|
+
return (
|
|
468
|
+
(
|
|
469
|
+
backup_service,
|
|
470
|
+
"backup_service",
|
|
471
|
+
"Run the declared backup for one service on its server, "
|
|
472
|
+
"writing a schema-valid receipt; requires confirm=true",
|
|
473
|
+
destructive,
|
|
474
|
+
),
|
|
475
|
+
(
|
|
476
|
+
verify_backup,
|
|
477
|
+
"verify_backup",
|
|
478
|
+
"Prove the newest backup of one service restores (dump "
|
|
479
|
+
"restore-check or snapshot integrity), receipted; requires "
|
|
480
|
+
"confirm=true",
|
|
481
|
+
destructive,
|
|
482
|
+
),
|
|
483
|
+
)
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
def _operator_registrations(
|
|
487
|
+
toolset: AgentToolset,
|
|
488
|
+
) -> tuple[_Registration, ...]:
|
|
489
|
+
read_only = ToolAnnotations(read_only_hint=True)
|
|
490
|
+
destructive = ToolAnnotations(read_only_hint=False, destructive_hint=True)
|
|
491
|
+
|
|
492
|
+
def operator_proposals() -> str:
|
|
493
|
+
return _dump(toolset.operator_proposals())
|
|
494
|
+
|
|
495
|
+
def operator_watch(
|
|
496
|
+
drift: bool = False, # noqa: FBT001, FBT002 - explicit agent flag.
|
|
497
|
+
) -> str:
|
|
498
|
+
return _dump(toolset.operator_watch(drift=drift))
|
|
499
|
+
|
|
500
|
+
def operator_approve(
|
|
501
|
+
proposal: str,
|
|
502
|
+
confirm: bool = False, # noqa: FBT001, FBT002 - explicit agent gate.
|
|
503
|
+
) -> str:
|
|
504
|
+
return _dump(toolset.operator_approve(proposal, confirm=confirm))
|
|
505
|
+
|
|
506
|
+
return (
|
|
507
|
+
(
|
|
508
|
+
operator_proposals,
|
|
509
|
+
"operator_proposals",
|
|
510
|
+
"List every operator proposal receipt: trigger evidence, "
|
|
511
|
+
"diagnosis, proposed operation, and outcome",
|
|
512
|
+
read_only,
|
|
513
|
+
),
|
|
514
|
+
(
|
|
515
|
+
operator_watch,
|
|
516
|
+
"operator_watch",
|
|
517
|
+
"Run one operator watch pass: fetch firing declared alerts "
|
|
518
|
+
"through the mTLS gateway (and audit for drift when "
|
|
519
|
+
"drift=true) and write proposals for anything new",
|
|
520
|
+
read_only,
|
|
521
|
+
),
|
|
522
|
+
(
|
|
523
|
+
operator_approve,
|
|
524
|
+
"operator_approve",
|
|
525
|
+
"Execute one operator proposal's declared remediation and "
|
|
526
|
+
"verify its trigger evidence resolves; requires confirm=true",
|
|
527
|
+
destructive,
|
|
528
|
+
),
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
def _dump(payload: dict[str, object]) -> str:
|
|
533
|
+
return json.dumps(payload, sort_keys=True)
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
def _parser() -> StrictArgumentParser:
|
|
537
|
+
parser = StrictArgumentParser(
|
|
538
|
+
prog="cloudfall-mcp",
|
|
539
|
+
description=(
|
|
540
|
+
"Expose the Cloudfall agent toolset over MCP stdio. Read-only"
|
|
541
|
+
" evidence tools are available freely; every server-changing"
|
|
542
|
+
" tool requires an explicit two-step confirmation handshake."
|
|
543
|
+
),
|
|
544
|
+
)
|
|
545
|
+
parser.add_argument(
|
|
546
|
+
"--project",
|
|
547
|
+
type=Path,
|
|
548
|
+
default=None,
|
|
549
|
+
help=(
|
|
550
|
+
f"project directory to run in (default: ${PROJECT_DIRECTORY_VARIABLE}, "
|
|
551
|
+
"else the current directory when it is a project)"
|
|
552
|
+
),
|
|
553
|
+
)
|
|
554
|
+
parser.add_argument(
|
|
555
|
+
"--schemas",
|
|
556
|
+
type=Path,
|
|
557
|
+
default=default_schema_directory(),
|
|
558
|
+
help=(
|
|
559
|
+
"JSON Schema directory used to validate the project "
|
|
560
|
+
"(default: %(default)s)"
|
|
561
|
+
),
|
|
562
|
+
)
|
|
563
|
+
parser.add_argument(
|
|
564
|
+
"--engine",
|
|
565
|
+
type=Path,
|
|
566
|
+
default=default_engine_directory(),
|
|
567
|
+
help="engine module directory containing the Ansible playbooks"
|
|
568
|
+
" (default: %(default)s)",
|
|
569
|
+
)
|
|
570
|
+
parser.add_argument(
|
|
571
|
+
"--inventory-file",
|
|
572
|
+
type=project_path_argument,
|
|
573
|
+
default=Path("tmp/ansible-inventory.json"),
|
|
574
|
+
help="path where the rendered Ansible inventory is written"
|
|
575
|
+
" (default: %(default)s)",
|
|
576
|
+
)
|
|
577
|
+
parser.add_argument(
|
|
578
|
+
"--observed",
|
|
579
|
+
type=project_path_argument,
|
|
580
|
+
default=Path("tmp/observed"),
|
|
581
|
+
help="directory holding read-only server observation snapshots"
|
|
582
|
+
" (default: %(default)s)",
|
|
583
|
+
)
|
|
584
|
+
parser.add_argument(
|
|
585
|
+
"--service-observed",
|
|
586
|
+
type=project_path_argument,
|
|
587
|
+
default=Path("tmp/observed-services"),
|
|
588
|
+
help="directory holding DNS, TLS, origin, and public route evidence"
|
|
589
|
+
" (default: %(default)s)",
|
|
590
|
+
)
|
|
591
|
+
parser.add_argument(
|
|
592
|
+
"--deployments",
|
|
593
|
+
type=project_path_argument,
|
|
594
|
+
default=Path("tmp/deployments"),
|
|
595
|
+
help="directory holding domain deployment receipts (default: %(default)s)",
|
|
596
|
+
)
|
|
597
|
+
parser.add_argument(
|
|
598
|
+
"--releases",
|
|
599
|
+
type=project_path_argument,
|
|
600
|
+
default=Path("tmp/releases"),
|
|
601
|
+
help="directory holding component release receipts (default: %(default)s)",
|
|
602
|
+
)
|
|
603
|
+
parser.add_argument(
|
|
604
|
+
"--artifacts",
|
|
605
|
+
type=project_path_argument,
|
|
606
|
+
default=Path("tmp/artifacts"),
|
|
607
|
+
help="directory holding built release artifacts (default: %(default)s)",
|
|
608
|
+
)
|
|
609
|
+
parser.add_argument(
|
|
610
|
+
"--data-migrations",
|
|
611
|
+
type=project_path_argument,
|
|
612
|
+
default=Path("tmp/data-migrations"),
|
|
613
|
+
help="directory holding data-migration receipts (default: %(default)s)",
|
|
614
|
+
)
|
|
615
|
+
parser.add_argument(
|
|
616
|
+
"--secrets-dir",
|
|
617
|
+
type=Path,
|
|
618
|
+
default=Path("secrets"),
|
|
619
|
+
help="sops-encrypted secrets directory (default: %(default)s)",
|
|
620
|
+
)
|
|
621
|
+
parser.add_argument(
|
|
622
|
+
"--env-dir",
|
|
623
|
+
type=project_path_argument,
|
|
624
|
+
default=Path("tmp/env"),
|
|
625
|
+
help="rendered environment file directory (default: %(default)s)",
|
|
626
|
+
)
|
|
627
|
+
parser.add_argument(
|
|
628
|
+
"--env-receipts",
|
|
629
|
+
type=project_path_argument,
|
|
630
|
+
default=Path("tmp/env-receipts"),
|
|
631
|
+
help="rendered environment receipt directory (default: %(default)s)",
|
|
632
|
+
)
|
|
633
|
+
parser.add_argument(
|
|
634
|
+
"--backups",
|
|
635
|
+
type=project_path_argument,
|
|
636
|
+
default=Path("tmp/backups"),
|
|
637
|
+
help="directory holding backup operation receipts (default: %(default)s)",
|
|
638
|
+
)
|
|
639
|
+
parser.add_argument(
|
|
640
|
+
"--proposals",
|
|
641
|
+
type=project_path_argument,
|
|
642
|
+
default=Path("tmp/operator/proposals"),
|
|
643
|
+
help="directory holding operator proposal receipts (default: %(default)s)",
|
|
644
|
+
)
|
|
645
|
+
parser.add_argument(
|
|
646
|
+
"--gateway-ca",
|
|
647
|
+
type=Path,
|
|
648
|
+
default=None,
|
|
649
|
+
help="CA bundle for the logging gateway's alerts route",
|
|
650
|
+
)
|
|
651
|
+
parser.add_argument(
|
|
652
|
+
"--gateway-cert",
|
|
653
|
+
type=Path,
|
|
654
|
+
default=None,
|
|
655
|
+
help="client certificate for the logging gateway's alerts route",
|
|
656
|
+
)
|
|
657
|
+
parser.add_argument(
|
|
658
|
+
"--gateway-key",
|
|
659
|
+
type=Path,
|
|
660
|
+
default=None,
|
|
661
|
+
help="client key for the logging gateway's alerts route",
|
|
662
|
+
)
|
|
663
|
+
return parser
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
def main(argv: Sequence[str] | None = None) -> int:
|
|
667
|
+
"""Run the MCP server over stdio."""
|
|
668
|
+
arguments = parse_arguments(_parser(), argv)
|
|
669
|
+
try:
|
|
670
|
+
with project_context(arguments.project, os.environ) as project_directory:
|
|
671
|
+
_serve(arguments, project_directory)
|
|
672
|
+
except ProjectError as error:
|
|
673
|
+
sys.stderr.write(f"{_dump(error.as_dict())}\n")
|
|
674
|
+
return 2
|
|
675
|
+
return 0
|
|
676
|
+
|
|
677
|
+
|
|
678
|
+
def _serve(arguments: argparse.Namespace, project_directory: Path) -> None:
|
|
679
|
+
config = AgentConfig(
|
|
680
|
+
project_directory=project_directory,
|
|
681
|
+
schema_directory=Path(arguments.schemas),
|
|
682
|
+
engine_directory=Path(arguments.engine),
|
|
683
|
+
inventory_file=Path(arguments.inventory_file),
|
|
684
|
+
observed_directory=Path(arguments.observed),
|
|
685
|
+
service_observed_directory=Path(arguments.service_observed),
|
|
686
|
+
deployments_directory=Path(arguments.deployments),
|
|
687
|
+
releases_directory=Path(arguments.releases),
|
|
688
|
+
artifacts_directory=Path(arguments.artifacts),
|
|
689
|
+
data_migrations_directory=Path(arguments.data_migrations),
|
|
690
|
+
backups_directory=Path(arguments.backups),
|
|
691
|
+
secrets_directory=Path(arguments.secrets_dir),
|
|
692
|
+
environment_directory=Path(arguments.env_dir),
|
|
693
|
+
environment_receipts_directory=Path(arguments.env_receipts),
|
|
694
|
+
proposals_directory=Path(arguments.proposals),
|
|
695
|
+
gateway_ca_path=arguments.gateway_ca,
|
|
696
|
+
gateway_certificate_path=arguments.gateway_cert,
|
|
697
|
+
gateway_key_path=arguments.gateway_key,
|
|
698
|
+
)
|
|
699
|
+
create_server(config).run(transport="stdio")
|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
def run() -> None:
|
|
703
|
+
"""Installed console-script entry point."""
|
|
704
|
+
raise SystemExit(main())
|