mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 10:59:59 +00:00
fix(mcp): hold three guarantees on every run, not only on the first
Home Assistant pinned the MCP service account to its read-only group when it created the account and never again, so an account promoted to administrator by hand kept every mutating tool that scope denies while the deploy stayed green, because nothing looked at the existing case. The group is now asserted on every run and a refusal aborts instead of passing. Nextcloud minted an app password under a fixed managed name and never revoked the previous one, so every run that found the stored password rejected added another valid token while the old ones kept full account access, accumulating across deploys. The mint is now preceded by a listing and the revocation of every token carrying that name. Both new tasks mask their output, because the listing names the account and its token ids even though the JSON strips the secrets. Prometheus ran with no query timeout, so its two-minute default applied: a query the adapter abandoned after fifteen seconds kept the server busy for the rest of it. The flag is now derived from the adapter's own limit and doubled, which gives the server room past the adapter's deadline while keeping the two from drifting apart. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
ce29195b64
commit
938426da01
4 files changed
+54
No files matched your search
@@ -163,6 +163,16 @@ async def ensure_service_account(admin_token):
|
||||
user_id = created["result"]["user"]["id"]
|
||||
|
||||
if existing:
|
||||
regrouped = await command(
|
||||
{
|
||||
"type": "config/auth/update",
|
||||
"user_id": user_id,
|
||||
"group_ids": [SERVICE_GROUP],
|
||||
}
|
||||
)
|
||||
if not regrouped.get("success"):
|
||||
raise SystemExit("MCP account group refused: " + json.dumps(regrouped))
|
||||
|
||||
changed = await command(
|
||||
{
|
||||
"type": "config/auth_provider/homeassistant/admin_change_password",
|
||||
|
||||
@@ -58,6 +58,47 @@
|
||||
delegate_to: "{{ NEXTCLOUD_HOST_NODE }}"
|
||||
run_once: true
|
||||
|
||||
- name: "🔍 List the app passwords the MCP account already holds"
|
||||
ansible.builtin.command:
|
||||
argv:
|
||||
- container
|
||||
- exec
|
||||
- -u
|
||||
- "{{ NEXTCLOUD_DOCKER_USER }}"
|
||||
- "{{ NEXTCLOUD_LOCAL_CID }}" # nocheck: container-exec-resolver
|
||||
- php
|
||||
- "{{ NEXTCLOUD_INTERNAL_OCC_COMMAND }}"
|
||||
- user:auth-tokens:list
|
||||
- "{{ NEXTCLOUD_MCP_USERNAME }}"
|
||||
- --output=json
|
||||
register: nextcloud_mcp_tokens_held
|
||||
changed_when: false
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
delegate_to: "{{ NEXTCLOUD_HOST_NODE }}"
|
||||
run_once: true
|
||||
|
||||
- name: "🧹 Revoke the app passwords an earlier run minted under the managed name"
|
||||
ansible.builtin.command:
|
||||
argv:
|
||||
- container
|
||||
- exec
|
||||
- -u
|
||||
- "{{ NEXTCLOUD_DOCKER_USER }}"
|
||||
- "{{ NEXTCLOUD_LOCAL_CID }}" # nocheck: container-exec-resolver
|
||||
- php
|
||||
- "{{ NEXTCLOUD_INTERNAL_OCC_COMMAND }}"
|
||||
- user:auth-tokens:delete
|
||||
- "{{ NEXTCLOUD_MCP_USERNAME }}"
|
||||
- "{{ item | string }}"
|
||||
loop: >-
|
||||
{{ nextcloud_mcp_tokens_held.stdout | from_json
|
||||
| selectattr('name', 'equalto', NEXTCLOUD_MCP_TOKEN_NAME)
|
||||
| map(attribute='id') | list }}
|
||||
changed_when: true
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
delegate_to: "{{ NEXTCLOUD_HOST_NODE }}"
|
||||
run_once: true
|
||||
|
||||
- name: "🔑 Mint an app password for the MCP clients"
|
||||
ansible.builtin.command:
|
||||
argv:
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
command:
|
||||
- "--config.file={{ PROMETHEUS_CONFIG_DOCKER }}"
|
||||
- "--storage.tsdb.path={{ lookup('volume', 'web-app-prometheus', 'data').target }}"
|
||||
- "--query.timeout={{ PROMETHEUS_QUERY_TIMEOUT }}"
|
||||
- "--web.enable-lifecycle"
|
||||
{{ lookup('container_volumes', service_name) | indent(4) }}
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@ BLACKBOX_CONTAINER: "{{ lookup('config', application_id, 'services.blackbox-expo
|
||||
CADVISOR_CONTAINER: "{{ lookup('config', application_id, 'services.cadvisor.name') }}"
|
||||
|
||||
NODE_EXPORTER_CONTAINER: "{{ lookup('config', application_id, 'services.node-exporter.name') }}"
|
||||
PROMETHEUS_QUERY_TIMEOUT: "{{ (lookup('config', application_id, 'mcp.limits.timeout_seconds') | int * 2) ~ 's' }}"
|
||||
|
||||
PROMETHEUS_MCP_ENABLED: "{{ lookup('config', application_id, 'mcp.enabled') | bool }}"
|
||||
PROMETHEUS_MCP_SERVICE_KEY: "prometheusmcp"
|
||||
PROMETHEUS_MCP_CONTAINER: "{{ lookup('config', application_id, 'services.prometheusmcp.name') }}"
|
||||
|
||||
Reference in new issue
Block a user