---
- name: "π List the accounts this instance knows"
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 list -c {{ GITEA_CONFIG }}
register: gitea_mcp_accounts
changed_when: false
delegate_to: "{{ GITEA_API_HOST_NODE }}"
run_once: true
- name: "π€ Create the account the MCP token belongs to"
ansible.builtin.shell: | # nocheck: container-exec-resolver runtime-resolved CID, delegated to the hosting node
container exec -i -e GITEA_MCP_USER_PASSWORD --user {{ GITEA_USER }} {{ GITEA_API_LOCAL_CID | quote }} sh -lc '
/app/gitea/gitea admin user create \
--username "{{ GITEA_MCP_USERNAME }}" \
--password "$GITEA_MCP_USER_PASSWORD" \
--email "{{ GITEA_MCP_USER_EMAIL }}" \
--must-change-password=false \
-c {{ GITEA_CONFIG }}
'
environment:
GITEA_MCP_USER_PASSWORD: "{{ GITEA_MCP_USER_PASSWORD }}"
when: GITEA_MCP_USERNAME not in gitea_mcp_accounts.stdout.split()
changed_when: true
delegate_to: "{{ GITEA_API_HOST_NODE }}"
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 -e GITEA_MCP_USER_PASSWORD --user {{ GITEA_USER }} {{ GITEA_API_LOCAL_CID | quote }} sh -lc '
/app/gitea/gitea admin user change-password \
--username "{{ GITEA_MCP_USERNAME }}" \
--password "$GITEA_MCP_USER_PASSWORD" \
--must-change-password=false \
-c {{ GITEA_CONFIG }}
'
environment:
GITEA_MCP_USER_PASSWORD: "{{ GITEA_MCP_USER_PASSWORD }}"
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 -e GITEA_MCP_BASIC_AUTH {{ GITEA_API_LOCAL_CID | quote }} sh -lc '
{{ lookup('timeout', 30) | curl(5, 0) }} -o /dev/null -w "%{http_code}" \
-X DELETE \
-u "$GITEA_MCP_BASIC_AUTH" \
"{{ GITEA_INTERNAL_API_URL ~ '/users/' ~ GITEA_MCP_USERNAME ~ '/tokens/' ~ GITEA_MCP_TOKEN_NAME }}"
'
environment:
GITEA_MCP_BASIC_AUTH: "{{ GITEA_MCP_USERNAME ~ ':' ~ GITEA_MCP_USER_PASSWORD }}"
register: gitea_mcp_token_revoke
changed_when: gitea_mcp_token_revoke.stdout | trim == '204'
failed_when: gitea_mcp_token_revoke.stdout | trim not in ['204', '404']
delegate_to: "{{ GITEA_API_HOST_NODE }}"
run_once: true
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
- name: "π Mint the personal access token MCP clients present"
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 generate-access-token \
--username {{ GITEA_MCP_USERNAME | quote }} \
--token-name {{ GITEA_MCP_TOKEN_NAME | quote }} \
--scopes {{ GITEA_MCP_TOKEN_SCOPES | quote }} \
--raw \
-c {{ GITEA_CONFIG }}
register: gitea_mcp_mint
changed_when: true
delegate_to: "{{ GITEA_API_HOST_NODE }}"
run_once: true
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
- name: "π§ Take the minted token from the mint output"
ansible.builtin.set_fact:
gitea_mcp_token: "{{ gitea_mcp_mint.stdout_lines | last | trim }}"
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
run_once: true
- name: "π Refuse an instance that issued no usable token"
ansible.builtin.assert:
that:
- gitea_mcp_token | length >= 40
fail_msg: >-
Gitea returned no access token, so every MCP client would be configured
with an empty bearer and fail at first use.
- name: "πΎ Persist the token so MCP clients can read it"
ansible.builtin.include_role:
name: sys-token-store
tasks_from: write.yml
vars:
sys_token_store_user_key: "{{ lookup('config', application_id, 'mcp.credential.owner') }}"
sys_token_store_app: "{{ application_id }}"
sys_token_store_token: "{{ gitea_mcp_token }}"
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"