mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-09 04:06:42 +00:00
fix(web-app-fider): put the design logo into the object store
With BLOB_STORAGE=s3 Fider reads blobs only from its bucket, so the logo the role wrote into the blobs table never showed: the header had no logo, the favicon stayed upstream's and the sign-in dialog loaded its image from login.fider.io. The role now writes tenants/<tenant id>/logos/infinito-design-logo.png into its bucket from inside the SeaweedFS container (credentials on stdin, curl --aws-sigv4, md5 compare so a repeated run reports UNCHANGED) and sets logo_bkey through the new logo_stored argument. With design or logo off it removes only its own key. The SeaweedFS storage check now proves the bucket write with a post attachment and deletes the post again. It used to upload a tenant logo, which replaces logo_bkey; the role sets that key only while it is empty, so the design logo would never have come back. changed_when compares the script output exactly, because a search for CHANGED also matches UNCHANGED. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
1ea0390347
commit
d912664538
8 files changed
+124
-96
No files matched your search
@@ -1,4 +1,3 @@
|
||||
# TODO
|
||||
|
||||
- With `services.sso.enabled` false the role creates no tenant: `tasks/00_core.yml` includes `tasks/01_setup_oidc.yml` (tenant bootstrap, administrator, activation, provider row) only under `FIDER_OIDC_ENABLED`. Upstream then redirects every route to its installation form `/signup`, which any visitor can submit (read from the task conditions and from `app/middlewares/tenant.go` and `app/handlers/signup.go` of the deployed commit `67c52826`; the compose stack of the design pass ran with `sso` on). Fider has no password sign-in, so such a deployment also has no account. Options: bootstrap tenant and administrator in every variant and keep only the provider row under the flag; or refuse `/signup` at the proxy while no tenant exists.
|
||||
- With the object store enabled (`BLOB_STORAGE=s3`) the board keeps upstream's favicon and shows no logo, and the sign-in dialog loads `https://login.fider.io/static/assets/logo.png` from the browser (measured on the compose stack before a logo was set: the image rendered in the dialog). Cause: `tasks/02_design.yml` places the logo in the `blobs` table, which the S3 blob store never reads, so `FIDER_DESIGN_LOGO_ENABLED` is false there and `tenants.logo_bkey` stays empty; upstream's upload route `POST /_api/admin/settings/general` needs a session cookie. Options: put the object `tenants/<tenant id>/logos/infinito-design-logo.png` into the role's bucket with the role's object store credentials and set `logo_bkey`; or upload through the app's API with a session obtained from the identity provider.
|
||||
@@ -9,7 +9,7 @@ const {
|
||||
galleryEnabled,
|
||||
tokenValue,
|
||||
} = require("./design");
|
||||
const { decodeDotenvQuotedValue, gotoOnion, performKeycloakLoginForm } = require("./personas");
|
||||
const { apiGetOnion, decodeDotenvQuotedValue, gotoOnion, performKeycloakLoginForm } = require("./personas");
|
||||
const { isServiceEnabled, skipUnlessServiceEnabled } = require("./service-gating");
|
||||
const { resolveTimeout } = require("./timeouts");
|
||||
const { clickFiderSsoButton } = require("./_shared");
|
||||
@@ -17,8 +17,6 @@ const { clickFiderSsoButton } = require("./_shared");
|
||||
const base = decodeDotenvQuotedValue(process.env.FIDER_BASE_URL || "").replace(/\/$/, "");
|
||||
const adminUsername = decodeDotenvQuotedValue(process.env.ADMIN_USERNAME || "");
|
||||
const adminPassword = decodeDotenvQuotedValue(process.env.ADMIN_PASSWORD || "");
|
||||
const title = decodeDotenvQuotedValue(process.env.DESIGN_TITLE || "");
|
||||
const logoEnabled = process.env.DESIGN_LOGO_ENABLED === "true";
|
||||
|
||||
const MODES = ["light", "dark"];
|
||||
const READY_MS = 60_000;
|
||||
@@ -270,14 +268,18 @@ exports.register = function () {
|
||||
});
|
||||
|
||||
test("design: the board carries the configured title", async ({ page }) => {
|
||||
const title = decodeDotenvQuotedValue(process.env.DESIGN_TITLE || "");
|
||||
test.skip(!title, "title replacement is disabled for this role");
|
||||
await openHome(page);
|
||||
expect(title, "DESIGN_TITLE must be set in the Playwright env file").toBeTruthy();
|
||||
await expect(page).toHaveTitle(title);
|
||||
await expect(page.locator(`${BRAND} h1`)).toHaveText(title);
|
||||
});
|
||||
|
||||
test("design: logo and favicon are the configured ones", async ({ page }) => {
|
||||
test.skip(!logoEnabled, "the role places the logo in the database blob store only; with the object store enabled the tenant keeps its own logo");
|
||||
test("design: logo and favicon are the configured ones", async ({ page, request }) => {
|
||||
test.skip(process.env.DESIGN_LOGO_ENABLED !== "true", "logo replacement is disabled for this role");
|
||||
const image = await apiGetOnion(request, `${base}/static/images/logos/infinito-design-logo.png?size=100`);
|
||||
expect(image.status(), "the logo blob is served from the active blob store").toBe(200);
|
||||
expect(image.headers()["content-type"]).toBe("image/png");
|
||||
await openHome(page);
|
||||
const logo = page.locator(`${BRAND} img`);
|
||||
await expect(logo).toBeVisible();
|
||||
@@ -288,6 +290,10 @@ exports.register = function () {
|
||||
const brandBox = await page.locator(BRAND).boundingBox();
|
||||
expect(brandBox.width, "logo and title form a wide brand").toBeGreaterThan(brandBox.height);
|
||||
await expect(page.locator("link[rel='icon']").first()).toHaveAttribute("href", LOGO_FAVICON);
|
||||
await page.locator(PRIMARY).first().click();
|
||||
await modalOpened(page);
|
||||
await expect(page.locator(`${MODAL} img`).first()).toHaveAttribute("src", LOGO_IMAGE);
|
||||
await expect(page.locator(`${MODAL} img[src*='login.fider.io']`)).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("design: the board follows the browser until the switch is used, then the switch wins", async ({ page }) => {
|
||||
|
||||
@@ -1,16 +1,3 @@
|
||||
// SeaweedFS object-store scenario for Fider.
|
||||
//
|
||||
// Fider is configured with the S3 blob backend (env.j2: BLOB_STORAGE=s3 +
|
||||
// BLOB_STORAGE_S3_BUCKET / _ACCESS_KEY_ID / _SECRET_ACCESS_KEY /
|
||||
// _ENDPOINT_URL / _REGION), so a tenant logo the administrator uploads on the
|
||||
// admin General settings page is written to the consumer bucket as a new
|
||||
// private blob (Fider stores blobs with ACL=private and reverse-proxies them
|
||||
// through its own /images route, which is why the role declares no public
|
||||
// flag). The action signs the administrator in through Fider's SSO button +
|
||||
// Keycloak form, opens the admin General settings page, sets the "Your Logo"
|
||||
// file input to a small PNG and clicks Save; the shared check proves the
|
||||
// bucket grew via the Filer UI.
|
||||
//
|
||||
// Required env (rendered by templates/playwright.env.j2):
|
||||
// FIDER_BASE_URL, the OIDC login vars consumed by performKeycloakLoginForm,
|
||||
// and the SEAWEEDFS_* keys consumed by runSeaweedfsStorageCheck.
|
||||
@@ -19,34 +6,21 @@ const { test, expect } = require("@playwright/test");
|
||||
const { resolveTimeout, isOnionTarget } = require("./timeouts");
|
||||
const { skipUnlessServiceEnabled } = require("./service-gating");
|
||||
const { runSeaweedfsStorageCheck, performKeycloakLoginForm, decodeDotenvQuotedValue } = require("./personas");
|
||||
const { clickFiderSsoButton } = require("./_shared");
|
||||
|
||||
const LOGO_PNG = Buffer.from(
|
||||
const ATTACHMENT_PNG_BASE64 =
|
||||
"iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAIAAAAiOjnJAAABeElEQVR42u3SMQ0AAAgEsVeHMDQhEBMM" +
|
||||
"DE2q4HKpHjgXCTAWxsJYYCyMhbHAWBgLY4GxMBbGAmNhLIwFxsJYGAuMhbEwFhgLY2EsMBbGwlhgLIyF" +
|
||||
"scBYGAtjgbEwFsYCY2EsjAXGwlgYC4yFsTAWGAtjYSwwFsbCWGAsjIWxwFgYC2OBsTAWxgJjYSyMBcbC" +
|
||||
"WBgLjIWxMBYYC2NhLDAWxsJYYCyMhbHAWBgLY4GxMBbGAmNhLIyFsVTAWBgLY4GxMBbGAmNhLIwFxsJY" +
|
||||
"GAuMhbEwFhgLY2EsMBbGwlhgLIyFscBYGAtjgbEwFsYCY2EsjAXGwlgYC4yFsTAWGAtjYSwwFsbCWGAs" +
|
||||
"jIWxwFgYC2OBsTAWxgJjYSyMBcbCWBgLjIWxMBYYC2NhLDAWxsJYYCyMhbHAWBgLY4GxMBbGAmNhLIyF" +
|
||||
"sVTAWBgLY4GxMBbGAmNhLIwFxsJYGAtjqYCxMBbGAmNhLIwFxsJYGAuMhbEwFhgLY2EsMBbGwlhgLIyF" +
|
||||
"scBYGAtjgbH4ZgHTqvyKw+KRzwAAAABJRU5ErkJggg==",
|
||||
"base64",
|
||||
);
|
||||
|
||||
async function clickFiderSsoButton(locator) {
|
||||
const signInLink = locator
|
||||
.getByRole("button", { name: /sign in/i })
|
||||
.or(locator.getByRole("link", { name: /sign in/i }));
|
||||
await signInLink.first().waitFor({ state: "visible", timeout: resolveTimeout(30_000) });
|
||||
await signInLink.first().click();
|
||||
|
||||
const ssoButton = locator.getByRole("link", { name: /continue with/i });
|
||||
await ssoButton.first().waitFor({ state: "visible", timeout: resolveTimeout(15_000) });
|
||||
await ssoButton.first().click({ force: true, timeout: resolveTimeout(30_000) });
|
||||
}
|
||||
"DE2q4HKpHjgXCTAWxsJYYCyMhbHAWBgLY4GxMBbGAmNhLIwFxsJYGAuMhbEwFhgLY2EsMBbGwlhgLIyF" +
|
||||
"scBYGAtjgbEwFsYCY2EsjAXGwlgYC4yFsTAWGAtjYSwwFsbCWGAsjIWxwFgYC2OBsTAWxgJjYSyMBcbC" +
|
||||
"WBgLjIWxMBYYC2NhLDAWxsJYYCyMhbHAWBgLY4GxMBbGAmNhLIyFsVTAWBgLY4GxMBbGAmNhLIwFxsJY" +
|
||||
"GAuMhbEwFhgLY2EsMBbGwlhgLIyFscBYGAtjgbEwFsYCY2EsjAXGwlgYC4yFsTAWGAtjYSwwFsbCWGAs" +
|
||||
"jIWxwFgYC2OBsTAWxgJjYSyMBcbCWBgLjIWxMBYYC2NhLDAWxsJYYCyMhbHAWBgLY4GxMBbGAmNhLIyF" +
|
||||
"sVTAWBgLY4GxMBbGAmNhLIwFxsJYGAtjqYCxMBbGAmNhLIwFxsJYGAuMhbEwFhgLY2EsMBbGwlhgLIyF" +
|
||||
"scBYGAtjgbH4ZgHTqvyKw+KRzwAAAABJRU5ErkJggg==";
|
||||
|
||||
test.use({ ignoreHTTPSErrors: true });
|
||||
|
||||
test("seaweedfs: an uploaded Fider tenant logo is stored in the SeaweedFS bucket", async ({ page, browser }) => {
|
||||
test("seaweedfs: a Fider post attachment is stored in the SeaweedFS bucket", async ({ page, browser }) => {
|
||||
test.skip(isOnionTarget(), "SeaweedFS filer UI is not a Tor surface on an onion node (headless backend)");
|
||||
skipUnlessServiceEnabled("seaweedfs");
|
||||
test.setTimeout(resolveTimeout(180_000));
|
||||
@@ -54,67 +28,52 @@ test("seaweedfs: an uploaded Fider tenant logo is stored in the SeaweedFS bucket
|
||||
const fiderBaseUrl = decodeDotenvQuotedValue(process.env.FIDER_BASE_URL || "");
|
||||
const adminUsername = decodeDotenvQuotedValue(process.env.ADMIN_USERNAME || "");
|
||||
const adminPassword = decodeDotenvQuotedValue(process.env.ADMIN_PASSWORD || "");
|
||||
const marker = `Storage check ${Date.now()}`;
|
||||
let post = null;
|
||||
|
||||
await runSeaweedfsStorageCheck(page, browser, {
|
||||
label: "a Fider admin tenant-logo upload",
|
||||
expectInPlaceOverwrite: true,
|
||||
label: "a Fider post attachment",
|
||||
action: async (appPage) => {
|
||||
expect(fiderBaseUrl, "FIDER_BASE_URL must be set for the Fider seaweedfs check").toBeTruthy();
|
||||
expect(adminUsername, "ADMIN_USERNAME must be set for the Fider seaweedfs check").toBeTruthy();
|
||||
expect(adminPassword, "ADMIN_PASSWORD must be set for the Fider seaweedfs check").toBeTruthy();
|
||||
|
||||
const baseUrl = fiderBaseUrl.replace(/\/$/, "");
|
||||
|
||||
await appPage.goto(`${baseUrl}/`, { waitUntil: "domcontentloaded" });
|
||||
await appPage.goto(`${fiderBaseUrl.replace(/\/$/, "")}/`, { waitUntil: "domcontentloaded" });
|
||||
await clickFiderSsoButton(appPage);
|
||||
await performKeycloakLoginForm(appPage, adminUsername, adminPassword);
|
||||
|
||||
await expect(
|
||||
appPage.locator(".c-menu-user").first(),
|
||||
"the administrator must be authenticated before opening the admin settings",
|
||||
"the administrator must be authenticated before creating the post",
|
||||
).toBeVisible({ timeout: resolveTimeout(60_000) });
|
||||
|
||||
await appPage.goto(`${baseUrl}/admin`, { waitUntil: "domcontentloaded" });
|
||||
|
||||
const fileInput = appPage.locator('input[type="file"][accept="image/*"]').first();
|
||||
await expect(
|
||||
fileInput,
|
||||
"the Fider admin General settings page must expose the 'Your Logo' image input",
|
||||
).toBeAttached({ timeout: resolveTimeout(60_000) });
|
||||
|
||||
const marker = `infinito-storage-check-${Date.now()}.png`;
|
||||
await fileInput.setInputFiles({
|
||||
name: marker,
|
||||
mimeType: "image/png",
|
||||
buffer: LOGO_PNG,
|
||||
});
|
||||
|
||||
await expect(
|
||||
appPage.locator('.c-image-upload img[src^="data:image"], .preview img[src^="data:image"]').first(),
|
||||
"the selected logo must be loaded into the form (preview rendered) before saving",
|
||||
).toBeVisible({ timeout: resolveTimeout(30_000) });
|
||||
|
||||
const saveButton = appPage.getByRole("button", { name: /^save$/i }).first();
|
||||
await expect(
|
||||
saveButton,
|
||||
"the Fider admin General settings page must expose a Save action that persists the logo",
|
||||
).toBeVisible({ timeout: resolveTimeout(60_000) });
|
||||
const [settingsResp] = await Promise.all([
|
||||
appPage.waitForResponse(
|
||||
(r) => /\/_api\/admin\/settings\/general/.test(r.url()) && r.request().method() === "POST",
|
||||
{ timeout: resolveTimeout(60_000) },
|
||||
),
|
||||
saveButton.click(),
|
||||
]);
|
||||
expect(
|
||||
settingsResp.ok(),
|
||||
`Fider must accept the General-settings save that persists the logo (got HTTP ${settingsResp.status()})`,
|
||||
).toBeTruthy();
|
||||
const reqBody = settingsResp.request().postData() || "";
|
||||
expect(
|
||||
reqBody,
|
||||
"the General-settings save must carry the logo upload payload (empty upload = silent no-op)",
|
||||
).toMatch(/"upload"\s*:\s*\{[^}]*"content"/);
|
||||
post = await appPage.evaluate(
|
||||
async ({ title, content }) => {
|
||||
const response = await fetch("/api/v1/posts", {
|
||||
method: "POST",
|
||||
headers: { Accept: "application/json", "Content-Type": "application/json" },
|
||||
credentials: "same-origin",
|
||||
body: JSON.stringify({
|
||||
title,
|
||||
description: "A post that proves attachments reach the object store.",
|
||||
attachments: [{ upload: { fileName: "storage-check.png", contentType: "image/png", content } }],
|
||||
}),
|
||||
});
|
||||
return { status: response.status, body: await response.json().catch(() => ({})) };
|
||||
},
|
||||
{ title: marker, content: ATTACHMENT_PNG_BASE64 },
|
||||
);
|
||||
expect(post.status, "Fider must accept the post with its attachment").toBe(200);
|
||||
},
|
||||
});
|
||||
|
||||
const removal = await page.evaluate(async (number) => {
|
||||
const response = await fetch(`/api/v1/posts/${number}`, {
|
||||
method: "DELETE",
|
||||
headers: { Accept: "application/json", "Content-Type": "application/json" },
|
||||
credentials: "same-origin",
|
||||
body: JSON.stringify({ text: "" }),
|
||||
});
|
||||
return response.status;
|
||||
}, post.body.number);
|
||||
expect(removal, "the storage-check post is removed again").toBe(200);
|
||||
});
|
||||
@@ -0,0 +1,32 @@
|
||||
#!/bin/sh
|
||||
# Args: action (put|delete), object URL, S3 region.
|
||||
# Stdin: "<access key>:<secret key>" on the first line; for put, the PNG as base64 after it.
|
||||
# Prints CHANGED, UNCHANGED, REMOVED or ABSENT.
|
||||
set -eu
|
||||
action=$1
|
||||
url=$2
|
||||
region=$3
|
||||
IFS= read -r credentials
|
||||
config() {
|
||||
printf 'user = "%s"\naws-sigv4 = "aws:amz:%s:s3"\nurl = "%s"\nsilent\nfail\n' "$credentials" "$region" "$url"
|
||||
}
|
||||
if [ "$action" = delete ]; then
|
||||
if config | curl -K - --head -o /dev/null; then
|
||||
config | curl -K - -X DELETE -o /dev/null
|
||||
echo REMOVED
|
||||
else
|
||||
echo ABSENT
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
body=$(mktemp)
|
||||
trap 'rm -f "$body"' EXIT
|
||||
base64 -d > "$body"
|
||||
wanted=$(md5sum < "$body" | cut -d' ' -f1)
|
||||
current=$(config | curl -K - | md5sum | cut -d' ' -f1)
|
||||
if [ "$current" = "$wanted" ]; then
|
||||
echo UNCHANGED
|
||||
exit 0
|
||||
fi
|
||||
config | curl -K - -X PUT -H 'Content-Type: image/png' --data-binary "@$body" -o /dev/null
|
||||
echo CHANGED
|
||||
@@ -1,4 +1,4 @@
|
||||
-- Args: title (empty keeps the name), bootstrap_name (the name the role bootstrapped the tenant with), css, logo_key, logo_base64 (empty keeps the logo).
|
||||
-- Args: title (empty keeps the name), bootstrap_name (the name the role bootstrapped the tenant with), css, logo_key, logo_base64 (non-empty writes the logo into the blobs table), logo_stored (non-empty when the logo is in the active blob store).
|
||||
-- Returns one row: the number of rows that changed.
|
||||
WITH tenant AS (
|
||||
SELECT id FROM tenants ORDER BY id LIMIT 1
|
||||
@@ -18,7 +18,7 @@ WITH tenant AS (
|
||||
THEN %(title)s ELSE tenants.name END AS name,
|
||||
CASE WHEN tenants.custom_css = '' OR position('--infinito-design-carrier' IN tenants.custom_css) > 0
|
||||
THEN %(css)s ELSE tenants.custom_css END AS custom_css,
|
||||
CASE WHEN %(logo_base64)s <> '' AND COALESCE(tenants.logo_bkey, '') = ''
|
||||
CASE WHEN %(logo_stored)s <> '' AND COALESCE(tenants.logo_bkey, '') = ''
|
||||
THEN %(logo_key)s ELSE tenants.logo_bkey END AS logo_bkey
|
||||
FROM tenants
|
||||
JOIN tenant ON tenant.id = tenants.id
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
-- Returns one row: the id of the tenant the role designs, 0 while no tenant exists.
|
||||
SELECT COALESCE(MIN(id), 0) FROM tenants;
|
||||
@@ -17,6 +17,34 @@
|
||||
register: fider_design_logo
|
||||
when: FIDER_DESIGN_LOGO_ENABLED | bool
|
||||
|
||||
- name: "🪣 Fider | Logo in the object store"
|
||||
when: FIDER_OBJSTORE_ENABLED | bool
|
||||
block:
|
||||
- name: "🪣 Fider | Read the tenant id"
|
||||
database_query:
|
||||
config: "{{ lookup('database', application_id) }}"
|
||||
query_file: "{{ role_path }}/files/sql/select-tenant-id.sql"
|
||||
expect_rows: true
|
||||
mask_values: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
register: fider_design_tenant
|
||||
changed_when: false
|
||||
|
||||
- name: "🪣 Fider | Store or remove the generated logo in the bucket"
|
||||
ansible.builtin.shell: >
|
||||
container exec -i {{ FIDER_OBJSTORE_CONTAINER_ADDRESS }}
|
||||
sh -c {{ lookup('file', 'shell/design-logo-object.sh') | quote }} design-logo-object
|
||||
{{ 'put' if FIDER_DESIGN_LOGO_ENABLED | bool else 'delete' }}
|
||||
{{ (lookup('objstore', application_id, 'url') ~ '/' ~ lookup('objstore', application_id, 'bucket') ~ '/tenants/' ~ fider_design_tenant.rows[0][0] ~ '/' ~
|
||||
FIDER_DESIGN_LOGO_KEY) | quote }}
|
||||
{{ lookup('objstore', application_id, 'region') | quote }}
|
||||
args:
|
||||
stdin: "{{ lookup('objstore', application_id, 'access_key') }}:{{ lookup('objstore', application_id, 'secret_key') }}\n{{ fider_design_logo.content if FIDER_DESIGN_LOGO_ENABLED
|
||||
| bool else '' }}"
|
||||
register: fider_design_logo_object
|
||||
changed_when: fider_design_logo_object.stdout in ['CHANGED', 'REMOVED']
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
when: fider_design_tenant.rows[0][0] | int > 0
|
||||
|
||||
- name: "🎨 Fider | Apply title, custom CSS and logo"
|
||||
database_query:
|
||||
config: "{{ lookup('database', application_id) }}"
|
||||
@@ -26,7 +54,8 @@
|
||||
bootstrap_name: "{{ SOFTWARE_NAME }}"
|
||||
css: "{{ lookup('template', 'custom.css.j2') }}"
|
||||
logo_key: "{{ FIDER_DESIGN_LOGO_KEY }}"
|
||||
logo_base64: "{{ fider_design_logo.content if FIDER_DESIGN_LOGO_ENABLED | bool else '' }}"
|
||||
logo_base64: "{{ fider_design_logo.content if FIDER_DESIGN_LOGO_ENABLED | bool and not (FIDER_OBJSTORE_ENABLED | bool) else '' }}"
|
||||
logo_stored: "{{ 'true' if FIDER_DESIGN_LOGO_ENABLED | bool else '' }}"
|
||||
expect_rows: true
|
||||
mask_values: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
register: fider_design_apply
|
||||
|
||||
@@ -8,9 +8,10 @@ FIDER_OIDC_ENABLED: "{{ lookup('config', application_id, 'services.sso.enabled')
|
||||
|
||||
FIDER_DESIGN_ENABLED: "{{ lookup('config', application_id, 'services.design.enabled') | bool }}"
|
||||
FIDER_DESIGN_TITLE: "{{ lookup('design', application_id).title if FIDER_DESIGN_ENABLED | bool and lookup('design', application_id).title is string else '' }}"
|
||||
FIDER_DESIGN_LOGO_ENABLED: "{{ FIDER_DESIGN_ENABLED | bool and lookup('design', application_id).logo is string and not (lookup('objstore', application_id, 'enabled')
|
||||
| bool) }}"
|
||||
FIDER_DESIGN_LOGO_ENABLED: "{{ FIDER_DESIGN_ENABLED | bool and lookup('design', application_id).logo is string }}"
|
||||
FIDER_DESIGN_LOGO_KEY: "logos/infinito-design-logo.png"
|
||||
FIDER_OBJSTORE_ENABLED: "{{ lookup('objstore', application_id, 'enabled') | bool }}"
|
||||
FIDER_OBJSTORE_CONTAINER_ADDRESS: "{{ lookup('container_address', lookup('objstore', application_id, 'id'), lookup('objstore', application_id, 'engine')) }}"
|
||||
|
||||
FIDER_TENANT_BOOTSTRAP_BODY:
|
||||
tenantName: "{{ SOFTWARE_NAME }}"
|
||||
|
||||
Reference in new issue
Block a user