feat(debyltech-cloud): limit customers to Files, Activity and signing
Nothing was group-restricted, so customers saw Dashboard, Photos, Office and the rest, plus Nextcloud's first-run and promo apps. - Disable for everyone: firstrunwizard, recommendations, related_resources, weather_status, survey_client, support, app_api, contactsinteraction, photos. A refused disable now fails the play (occ exits 0 on "can't be disabled"). - Restrict dashboard and office to staff. defaultapp=dashboard,files so staff land on the dashboard and customers fall through to Files. - libresign groups_request_sign pinned to staff and asserted in verify. LibreSign itself is deliberately NOT group-restricted: that also blocks anonymous requests and would break public signing links. - profile.enabled=false; lookup_server="" (lookup_server_connector can't be disabled). - README: what customers can open. Checked as a probe customer: apps=files,activity,libresign,text,viewer, lands in Files, can't request signatures; staff land on Dashboard. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
c4fe506860
commit
0cc4c1460e
@@ -183,8 +183,16 @@ What a customer gets:
|
|||||||
- no view of other accounts or groups: the share search and contacts menu
|
- no view of other accounts or groups: the share search and contacts menu
|
||||||
return nothing
|
return nothing
|
||||||
|
|
||||||
|
What they can open: Files, Activity, and LibreSign for signing only.
|
||||||
|
Dashboard and Office are staff-only. Promotional or directory-style apps
|
||||||
|
(first-run wizard, recommendations, weather, Photos, contacts interaction,
|
||||||
|
lookup server, ...) are disabled for everyone. Only staff can *request*
|
||||||
|
signatures.
|
||||||
|
|
||||||
Signature requests to customers need no account: use LibreSign with their
|
Signature requests to customers need no account: use LibreSign with their
|
||||||
email address.
|
email address. LibreSign stays enabled for all accounts on purpose.
|
||||||
|
Restricting an app to a group also blocks visitors who aren't logged in,
|
||||||
|
which would break the public signing links.
|
||||||
|
|
||||||
## Logging
|
## Logging
|
||||||
|
|
||||||
|
|||||||
@@ -530,6 +530,79 @@
|
|||||||
changed_when: "'CHANGED' in debyltech_staff_quota.stdout"
|
changed_when: "'CHANGED' in debyltech_staff_quota.stdout"
|
||||||
loop: "{{ cloud_debyltech_staff_users }}"
|
loop: "{{ cloud_debyltech_staff_users }}"
|
||||||
|
|
||||||
|
# What a customer can reach. Nextcloud had nothing group-restricted, so every
|
||||||
|
# customer saw Dashboard, Photos, Office and the rest in the app menu.
|
||||||
|
#
|
||||||
|
# Disabled outright -- promos, prompts, or directory-ish features a business
|
||||||
|
# file-and-signing portal has no use for (contactsinteraction silently adds
|
||||||
|
# whoever shares with you to your address book; app_api only produces a
|
||||||
|
# setup warning here). lookup_server_connector cannot be disabled (occ refuses)
|
||||||
|
# -- the empty `lookup_server` system value below switches it off instead.
|
||||||
|
#
|
||||||
|
# Restricted to staff: dashboard and office. `defaultapp` below lists
|
||||||
|
# dashboard first so staff land there and customers fall through to Files.
|
||||||
|
#
|
||||||
|
# NOT restricted: libresign. A group restriction is enforced for anonymous
|
||||||
|
# requests too (AppManager::checkAppForUser returns false for no user), so it
|
||||||
|
# would break the public signing links sent to outside signers and to any
|
||||||
|
# customer already logged in. Who may AUTHOR requests is LibreSign's own
|
||||||
|
# groups_request_sign, pinned to staff below.
|
||||||
|
- name: disable unneeded apps in debyltech-cloud
|
||||||
|
become: true
|
||||||
|
become_user: "{{ podman_user }}"
|
||||||
|
ansible.builtin.shell: |
|
||||||
|
set -o pipefail
|
||||||
|
occ() { podman exec -u www-data debyltech-cloud php occ "$@"; }
|
||||||
|
if occ app:list --output=json | python3 -c 'import json,sys; sys.exit(0 if sys.argv[1] in json.load(sys.stdin)["enabled"] else 1)' {{ item | quote }}; then
|
||||||
|
occ app:disable {{ item | quote }}
|
||||||
|
echo CHANGED
|
||||||
|
fi
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: debyltech_app_disable
|
||||||
|
changed_when: "'CHANGED' in debyltech_app_disable.stdout"
|
||||||
|
# occ exits 0 even when it refuses ("can't be disabled").
|
||||||
|
failed_when: debyltech_app_disable.rc != 0 or "can't be disabled" in debyltech_app_disable.stdout
|
||||||
|
loop:
|
||||||
|
- firstrunwizard
|
||||||
|
- recommendations
|
||||||
|
- related_resources
|
||||||
|
- weather_status
|
||||||
|
- survey_client
|
||||||
|
- support
|
||||||
|
- app_api
|
||||||
|
- contactsinteraction
|
||||||
|
- photos
|
||||||
|
|
||||||
|
- name: restrict staff-only apps in debyltech-cloud
|
||||||
|
become: true
|
||||||
|
become_user: "{{ podman_user }}"
|
||||||
|
ansible.builtin.shell: |
|
||||||
|
set -o pipefail
|
||||||
|
occ() { podman exec -u www-data debyltech-cloud php occ "$@"; }
|
||||||
|
want={{ [cloud_debyltech_staff_group] | to_json | quote }}
|
||||||
|
if [ "$(occ config:app:get {{ item | quote }} enabled || true)" != "$want" ]; then
|
||||||
|
occ app:enable --groups {{ cloud_debyltech_staff_group | quote }} {{ item | quote }} >/dev/null
|
||||||
|
echo CHANGED
|
||||||
|
fi
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: debyltech_app_restrict
|
||||||
|
changed_when: "'CHANGED' in debyltech_app_restrict.stdout"
|
||||||
|
loop:
|
||||||
|
- dashboard
|
||||||
|
- office
|
||||||
|
|
||||||
|
- name: pin who may request libresign signatures in debyltech-cloud
|
||||||
|
become: true
|
||||||
|
become_user: "{{ podman_user }}"
|
||||||
|
ansible.builtin.command: >
|
||||||
|
podman exec -u www-data debyltech-cloud
|
||||||
|
php occ config:app:set libresign groups_request_sign
|
||||||
|
--value={{ [cloud_debyltech_staff_group] | to_json | quote }}
|
||||||
|
register: debyltech_request_sign
|
||||||
|
changed_when: "'is now set to' in debyltech_request_sign.stdout"
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Branding: debyltechmail, cloned from skudakmail. custom_apps is a persisted
|
# Branding: debyltechmail, cloned from skudakmail. custom_apps is a persisted
|
||||||
# bind mount, so only enabling and config need reasserting.
|
# bind mount, so only enabling and config need reasserting.
|
||||||
@@ -608,6 +681,13 @@
|
|||||||
# than Nextcloud's sample Manual/intro video/Readme and Templates folder.
|
# than Nextcloud's sample Manual/intro video/Readme and Templates folder.
|
||||||
- {k: skeletondirectory, v: ""}
|
- {k: skeletondirectory, v: ""}
|
||||||
- {k: templatedirectory, v: ""}
|
- {k: templatedirectory, v: ""}
|
||||||
|
# First ENABLED app wins: staff get the dashboard, and customers -- who
|
||||||
|
# cannot open it (restricted below) -- fall through to Files.
|
||||||
|
- {k: defaultapp, v: "dashboard,files"}
|
||||||
|
# No per-account profile pages.
|
||||||
|
- {k: profile.enabled, v: "false", t: boolean}
|
||||||
|
# Never query or publish to the global lookup server (lookup.nextcloud.com).
|
||||||
|
- {k: lookup_server, v: ""}
|
||||||
- {k: loglevel, v: "2", t: integer}
|
- {k: loglevel, v: "2", t: integer}
|
||||||
- {k: log_rotate_size, v: "10485760", t: integer}
|
- {k: log_rotate_size, v: "10485760", t: integer}
|
||||||
- {k: mail_template_class, v: "OCA\\Debyltechmail\\Mail\\DebyltechEMailTemplate"}
|
- {k: mail_template_class, v: "OCA\\Debyltechmail\\Mail\\DebyltechEMailTemplate"}
|
||||||
|
|||||||
@@ -165,6 +165,14 @@ foreach ($isolation as $key => $want) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only staff may AUTHOR signature requests (LibreSign cannot be group-
|
||||||
|
// restricted without breaking its public signing links).
|
||||||
|
$requesters = json_decode($appConfig->getValueString('libresign', 'groups_request_sign', ''), true);
|
||||||
|
if ($requesters !== ['{{ cloud_debyltech_staff_group }}']) {
|
||||||
|
$failures[] = 'libresign groups_request_sign is ' . json_encode($requesters)
|
||||||
|
. ' -- expected only the staff group, or customers could send signature requests';
|
||||||
|
}
|
||||||
|
|
||||||
$identDocs = $appConfig->getValueString('libresign', 'identification_documents', '');
|
$identDocs = $appConfig->getValueString('libresign', 'identification_documents', '');
|
||||||
if ($identDocs !== '0') {
|
if ($identDocs !== '0') {
|
||||||
$failures[] = 'libresign identification_documents is "' . $identDocs
|
$failures[] = 'libresign identification_documents is "' . $identDocs
|
||||||
|
|||||||
@@ -85,6 +85,15 @@ for u in {{ podman_prune_ci_users | join(' ') }}; do
|
|||||||
# are rebuilt or re-pulled from the registry only when missing, so pruning
|
# are rebuilt or re-pulled from the registry only when missing, so pruning
|
||||||
# them just forces a multi-GB re-download on the next job.
|
# them just forces a multi-GB re-download on the next job.
|
||||||
prune_user "$u" "{{ podman_prune_ci_until }}" yes --filter "label!={{ podman_prune_ci_keep_label }}"
|
prune_user "$u" "{{ podman_prune_ci_until }}" yes --filter "label!={{ podman_prune_ci_keep_label }}"
|
||||||
|
|
||||||
|
# ...but the label is inherited by every build of those images, including the
|
||||||
|
# one a rebuild supersedes. That copy loses its tag and becomes dangling, and
|
||||||
|
# the label filter above would keep it forever -- a multi-GB leak per weekly
|
||||||
|
# rebuild, ESP-IDF alone being several GB. Without -a, `image prune` removes
|
||||||
|
# only dangling images, so it can ignore the label without touching the live
|
||||||
|
# tagged ones.
|
||||||
|
dangling=$(run "$u" image prune -f --filter "until={{ podman_prune_ci_until }}" 2>&1 | tail -1)
|
||||||
|
log "user=$u dangling_prune=${dangling:-none}"
|
||||||
done
|
done
|
||||||
|
|
||||||
log "status=ok"
|
log "status=ok"
|
||||||
|
|||||||
Reference in New Issue
Block a user