mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 10:59:59 +00:00
Symfony ArgvInput reads a token beginning with a dash as an option, so passing the secret as a separate token after --value handed occ two tokens and occ reported the option as missing its value. Doorkeeper mints base64url secrets, so roughly one run in 43 produced one starting with a dash and the OpenProject provisioning died with: The "--value" option requires a value. The equals form is unambiguous: Symfony splits at the first equals sign and takes everything after it as the value. The quote filter replaces the hand-written single quotes and stays shell-safe. Note that shlex leaves a leading-dash value unquoted, so the equals form is what carries the fix, not the quoting. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
111 lines
5.7 KiB
YAML
111 lines
5.7 KiB
YAML
---
|
|
- name: "🔍 Resolve the OpenProject web hosting node and container id"
|
|
ansible.builtin.include_tasks: "{{ lookup('path_absolute', 'roles/sys-svc-compose/tasks/utils/swarm/resolve_host_cid.yml') }}"
|
|
vars:
|
|
resolve_service_key: web
|
|
resolve_service_name: "{{ lookup('container_service', 'web-app-openproject', 'web') }}"
|
|
resolve_output_prefix: NEXTCLOUD_OPENPROJECT
|
|
resolve_compose_cid: "{{ NEXTCLOUD_OPENPROJECT_CONTAINER_ADDRESS }}"
|
|
resolve_converge_retries: 120
|
|
resolve_converge_delay: 5
|
|
|
|
- name: ⏳ Wait for the OpenProject web endpoint
|
|
wait_for:
|
|
host: "{{ DOCKER_REACH_HOST }}"
|
|
port: "{{ lookup('config', 'web-app-openproject', 'services.openproject.ports.local.http') }}"
|
|
delay: 5
|
|
timeout: "{{ lookup('timeout', 600) | int }}"
|
|
|
|
- name: 📁 Create the Nextcloud storage + OpenProject OAuth application
|
|
ansible.builtin.shell:
|
|
cmd: >- # nocheck: container-exec-resolver NEXTCLOUD_OPENPROJECT_LOCAL_CID resolved at delegate_to runtime; container_address would return a manager-only subshell
|
|
container exec -i
|
|
-e NEXTCLOUD_HOST={{ lookup('tls', 'web-app-nextcloud', 'url.base') | quote }}
|
|
-e STORAGE_NAME={{ nextcloud_op_storage_name | quote }}
|
|
-e NC_HAS_OP_SECRET={{ nextcloud_op_client_secret_current.stdout | trim | quote }}
|
|
{{ NEXTCLOUD_OPENPROJECT_LOCAL_CID | quote }}
|
|
bash -lc 'cd /app && bundle exec rails runner -'
|
|
stdin: "{{ lookup('file', 'ruby/utils/doorkeeper_allow_onion_redirect.rb') ~ '\n' ~ lookup('file', 'ruby/addons/openproject/ensure_nextcloud_storage.rb') }}"
|
|
delegate_to: "{{ NEXTCLOUD_OPENPROJECT_HOST_NODE }}"
|
|
register: nextcloud_op_storage_create
|
|
changed_when: "'\"oauth_application_created\":true' in nextcloud_op_storage_create.stdout"
|
|
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
|
|
|
- name: 🔎 Parse the OpenProject OAuth application credentials
|
|
set_fact:
|
|
nextcloud_op_oauth: "{{ nextcloud_op_storage_create.stdout | regex_search('{.*}') | from_json }}"
|
|
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
|
|
|
- name: 🔍 Resolve the effective OpenProject OAuth client secret (fresh or persisted)
|
|
set_fact:
|
|
nextcloud_op_client_secret: >-
|
|
{{ nextcloud_op_oauth.openproject_client_secret
|
|
| default((nextcloud_op_client_secret_current.stdout | trim), true) }}
|
|
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
|
|
|
- name: 🛑 Fail when no usable OpenProject OAuth application secret is available
|
|
assert:
|
|
that:
|
|
- nextcloud_op_oauth.openproject_client_id | default('') | length > 0
|
|
- (nextcloud_op_client_secret | default('') | trim) | length > 0
|
|
fail_msg: >-
|
|
OpenProject did not return a usable OAuth application and no client secret is persisted in
|
|
Nextcloud. A freshly generated client secret is only available the first time the application
|
|
is created; reset the integration_openproject app config (openproject_client_id,
|
|
openproject_client_secret, nc_oauth_client_id) and the OpenProject storage to re-provision.
|
|
|
|
- name: ⬆️ Push the OpenProject OAuth application credentials into Nextcloud
|
|
shell: >
|
|
{{ NEXTCLOUD_DOCKER_EXEC_OCC }} config:app:set integration_openproject {{ item.key }}
|
|
--value={{ item.value | quote }}
|
|
loop:
|
|
- { key: "authorization_method", value: "oauth2" }
|
|
- { key: "openproject_client_id", value: "{{ nextcloud_op_oauth.openproject_client_id }}" }
|
|
- { key: "openproject_client_secret", value: "{{ nextcloud_op_client_secret }}" }
|
|
loop_control:
|
|
label: "{{ item.key }}"
|
|
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
|
|
|
- name: 📝 Register a Nextcloud OAuth2 client for OpenProject
|
|
shell: >
|
|
{{ NEXTCLOUD_DOCKER_EXEC_OCC }} oauth2:add-client
|
|
"OpenProject client"
|
|
"{{ nextcloud_op_expected_url }}/oauth_clients/%s/callback"
|
|
--output=json
|
|
register: nextcloud_op_ncclient_create
|
|
changed_when: nextcloud_op_ncclient_create.rc == 0
|
|
failed_when: false
|
|
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
|
|
|
- name: 🔌 Wire the Nextcloud OAuth2 client into both sides when it was created
|
|
when: (nextcloud_op_ncclient_create.rc | default(1)) == 0
|
|
block:
|
|
- name: 🔎 Parse the Nextcloud OAuth2 client credentials
|
|
set_fact:
|
|
nextcloud_op_ncclient: "{{ nextcloud_op_ncclient_create.stdout | trim | from_json }}"
|
|
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
|
|
|
- name: ⬆️ Push the Nextcloud OAuth2 client id into integration_openproject
|
|
shell: >
|
|
{{ NEXTCLOUD_DOCKER_EXEC_OCC }} config:app:set integration_openproject nc_oauth_client_id
|
|
--value={{ nextcloud_op_ncclient.clientId | quote }}
|
|
changed_when: true
|
|
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
|
|
|
- name: 📝 Register the Nextcloud OAuth2 client back on the OpenProject storage
|
|
ansible.builtin.shell:
|
|
cmd: >- # nocheck: container-exec-resolver NEXTCLOUD_OPENPROJECT_LOCAL_CID resolved at delegate_to runtime; container_address would return a manager-only subshell
|
|
container exec -i
|
|
-e NEXTCLOUD_HOST={{ lookup('tls', 'web-app-nextcloud', 'url.base') | quote }}
|
|
-e STORAGE_NAME={{ nextcloud_op_storage_name | quote }}
|
|
-e NC_OAUTH_CLIENT_ID={{ nextcloud_op_ncclient.clientId | quote }}
|
|
-e NC_OAUTH_CLIENT_SECRET={{ nextcloud_op_ncclient.clientSecret | quote }}
|
|
{{ NEXTCLOUD_OPENPROJECT_LOCAL_CID | quote }}
|
|
bash -lc 'cd /app && bundle exec rails runner -'
|
|
stdin: "{{ lookup('file', 'ruby/utils/doorkeeper_allow_onion_redirect.rb') ~ '\n' ~ lookup('file', 'ruby/addons/openproject/ensure_nextcloud_storage.rb')
|
|
}}"
|
|
delegate_to: "{{ NEXTCLOUD_OPENPROJECT_HOST_NODE }}"
|
|
register: nextcloud_op_client_store
|
|
changed_when: true
|
|
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|