mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 02:54:26 +00:00
fix(mcp): set the service account password on every run, not only at creation
Four roles created their MCP service account and never touched its password again, while the same play authenticates as that account moments later. A deployment whose declared password moved on therefore failed at the login, not at the point the drift was introduced. gitea now runs 'admin user change-password' before the token dance. The --must-change-password=false flag is mandatory rather than cosmetic: at the pinned v1.27.1 the flag defaults to true, so omitting it locks the account out of the very API call that follows. nextcloud resets through 'occ user:resetpassword --password-from-env' before minting the app token that verifies the password. snipe-it compared nothing at all - its docstring promised to pin the password while the assignment sat inside the create branch. It now rehashes only when Hash::check says the stored hash no longer matches, so the changed flag stays honest. home assistant swallowed a failed credential creation for accounts that already existed and then logged in with them. It now calls admin_change_password and falls back to creation only when the reply is credentials_not_found. jellyfin and zammad already converged; wordpress, gitlab and moodle never authenticate with this password and are left alone. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
9a72d01eb6
commit
e3caa074b2
4 files changed
+52
-2
No files matched your search
@@ -23,6 +23,19 @@
|
||||
run_once: true
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
|
||||
- name: "🔑 Set the account's password to the one this deployment declares"
|
||||
ansible.builtin.shell: | # nocheck: container-exec-resolver runtime-resolved CID, delegated to the hosting node
|
||||
container exec -i --user {{ GITEA_USER }} {{ GITEA_API_LOCAL_CID | quote }} \
|
||||
/app/gitea/gitea admin user change-password \
|
||||
--username {{ GITEA_MCP_USERNAME | quote }} \
|
||||
--password {{ GITEA_MCP_USER_PASSWORD | quote }} \
|
||||
--must-change-password=false \
|
||||
-c {{ GITEA_CONFIG }}
|
||||
changed_when: true
|
||||
delegate_to: "{{ GITEA_API_HOST_NODE }}"
|
||||
run_once: true
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
|
||||
- name: "🗑 Revoke an access token left over under the same name"
|
||||
ansible.builtin.shell: | # nocheck: container-exec-resolver runtime-resolved CID, delegated to the hosting node
|
||||
container exec -i {{ GITEA_API_LOCAL_CID | quote }} \
|
||||
|
||||
@@ -159,6 +159,19 @@ async def ensure_service_account(admin_token):
|
||||
raise SystemExit("MCP account refused: " + json.dumps(created))
|
||||
user_id = created["result"]["user"]["id"]
|
||||
|
||||
if existing:
|
||||
changed = await command(
|
||||
{
|
||||
"type": "config/auth_provider/homeassistant/admin_change_password",
|
||||
"user_id": user_id,
|
||||
"password": SERVICE_PASSWORD,
|
||||
}
|
||||
)
|
||||
if changed.get("success"):
|
||||
return False
|
||||
if (changed.get("error") or {}).get("code") != "credentials_not_found":
|
||||
raise SystemExit("MCP account password refused: " + json.dumps(changed))
|
||||
|
||||
credentials = await command(
|
||||
{
|
||||
"type": "config/auth_provider/homeassistant/create",
|
||||
@@ -167,7 +180,7 @@ async def ensure_service_account(admin_token):
|
||||
"password": SERVICE_PASSWORD,
|
||||
}
|
||||
)
|
||||
if not credentials.get("success") and not existing:
|
||||
if not credentials.get("success"):
|
||||
raise SystemExit("MCP account credentials refused")
|
||||
return not existing
|
||||
|
||||
|
||||
@@ -38,6 +38,26 @@
|
||||
delegate_to: "{{ NEXTCLOUD_HOST_NODE }}"
|
||||
run_once: true
|
||||
|
||||
- name: "🔑 Set the account's password to the one this deployment declares"
|
||||
ansible.builtin.command:
|
||||
argv:
|
||||
- container
|
||||
- exec
|
||||
- -u
|
||||
- "{{ NEXTCLOUD_DOCKER_USER }}"
|
||||
- -e
|
||||
- "OC_PASS={{ NEXTCLOUD_MCP_USER_PASSWORD }}"
|
||||
- "{{ NEXTCLOUD_LOCAL_CID }}" # nocheck: container-exec-resolver
|
||||
- php
|
||||
- "{{ NEXTCLOUD_INTERNAL_OCC_COMMAND }}"
|
||||
- user:resetpassword
|
||||
- --password-from-env
|
||||
- "{{ NEXTCLOUD_MCP_USERNAME }}"
|
||||
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:
|
||||
|
||||
@@ -90,8 +90,12 @@ if (!$user) {
|
||||
$user->first_name = "MCP";
|
||||
$user->last_name = "Adapter";
|
||||
$user->username = $username;
|
||||
$user->password = bcrypt($password);
|
||||
$user->activated = 1;
|
||||
$user->password = bcrypt($password);
|
||||
$user->save();
|
||||
$changed = true;
|
||||
} elseif (!\Illuminate\Support\Facades\Hash::check($password, (string) $user->password)) {
|
||||
$user->password = bcrypt($password);
|
||||
$user->save();
|
||||
$changed = true;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user