mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-03 16:10:21 +00:00
Co-authored-by: Bhargav <BJP232004@GMAIL.COM> Co-authored-by: Hengfei Yang <hengfei.yang@gmail.com>
84 lines
4.0 KiB
JavaScript
84 lines
4.0 KiB
JavaScript
/**
|
|
* Thin authenticated REST client for the destination/template/user endpoints.
|
|
* Used by the DL suite to verify what the UI actually persisted — the form can
|
|
* echo your input while the stored value differs (trimming, lowercasing,
|
|
* empty entries), so every storage assertion reads the API, not the field.
|
|
*/
|
|
const BASE = process.env.ZO_BASE_URL || 'http://localhost:5080';
|
|
const ORG = process.env.ORGNAME || 'default';
|
|
const USER = process.env.ZO_ROOT_USER_EMAIL || 'root@example.com';
|
|
// The repo's documented default for local runs — the same value playwright.yml
|
|
// commits publicly. Not a secret; CI and any real environment override it.
|
|
const PASS = process.env.ZO_ROOT_USER_PASSWORD || 'Complexpass#123';
|
|
const AUTH = 'Basic ' + Buffer.from(`${USER}:${PASS}`).toString('base64');
|
|
|
|
async function req(method, path, body) {
|
|
const res = await fetch(`${BASE}/api/${ORG}${path}`, {
|
|
method,
|
|
headers: { Authorization: AUTH, 'Content-Type': 'application/json' },
|
|
body: body === undefined ? undefined : JSON.stringify(body),
|
|
});
|
|
const text = await res.text();
|
|
let json = null;
|
|
try { json = JSON.parse(text); } catch (_) { /* non-JSON body */ }
|
|
return { status: res.status, body: json, text };
|
|
}
|
|
|
|
const getDestination = (name) => req('GET', `/alerts/destinations/${name}`);
|
|
const listDestinations = () => req('GET', '/alerts/destinations');
|
|
const createDestination = (payload) => req('POST', '/alerts/destinations', payload);
|
|
const deleteDestination = (name) => req('DELETE', `/alerts/destinations/${name}`);
|
|
const testDestination = (payload) => req('POST', '/alerts/destinations/test', payload);
|
|
const listTemplates = () => req('GET', '/alerts/templates');
|
|
|
|
/**
|
|
* A destination recipient must be a user of the org — see the membership gate in
|
|
* alerts/destinations.rs. A distribution-list alias is not a person, so the DL
|
|
* fan-out case has to enrol the alias before it can be addressed at all.
|
|
*
|
|
* role MUST be 'admin': UserRoleRequest::from() (common/src/meta/user.rs) matches
|
|
* the requested role string against get_roles() and, on no match, treats it as a
|
|
* CUSTOM role — which core/src/users.rs::post_user rejects outright with 400 when
|
|
* OpenFGA/RBAC is off (the OSS CI topology this suite actually runs in restricts
|
|
* the standard-role set to Admin only). A lower role 400s the create outright,
|
|
* which is worse for the "stray privileged account" concern this once tried to
|
|
* avoid — cleanup being flag-gated (see dlUserCreated below) is the real mitigation.
|
|
*/
|
|
const createOrgUser = (email) => req('POST', '/users', {
|
|
email, first_name: 'dl', last_name: 'alias',
|
|
password: PASS,
|
|
role: 'admin',
|
|
});
|
|
const deleteOrgUser = (email) => req('DELETE', `/users/${encodeURIComponent(email)}`);
|
|
const getTemplate = (name) => req('GET', `/alerts/templates/${name}`);
|
|
const listOrgUsers = () => req('GET', '/users');
|
|
const listServiceAccounts = () => req('GET', '/service_accounts');
|
|
|
|
/**
|
|
* Every address the recipients picker may offer — the org's users plus its
|
|
* service accounts, lowercased. It is the picker's own option source, so a case
|
|
* can prove an offered value really is an account of this org (and that an
|
|
* outsider is not one) instead of taking the list on trust.
|
|
*/
|
|
async function orgAccounts() {
|
|
const responses = await Promise.all([listOrgUsers(), listServiceAccounts()]);
|
|
const emails = responses.flatMap((r) =>
|
|
(Array.isArray(r.body?.data) ? r.body.data : [])
|
|
.map((account) => String(account?.email ?? '').toLowerCase()),
|
|
);
|
|
return [...new Set(emails.filter(Boolean))];
|
|
}
|
|
|
|
/** Stored recipients for a destination, or null when it does not exist. */
|
|
async function storedRecipients(name) {
|
|
const r = await getDestination(name);
|
|
if (r.status !== 200 || !r.body) return null;
|
|
return r.body.emails;
|
|
}
|
|
|
|
module.exports = {
|
|
BASE, ORG, req, getDestination, listDestinations, createDestination,
|
|
deleteDestination, testDestination, listTemplates, getTemplate, storedRecipients,
|
|
createOrgUser, deleteOrgUser, listOrgUsers, listServiceAccounts, orgAccounts,
|
|
};
|