sc-site-sync/lib/common/syncConstants.js
2026-10-19 01:25:16 -05:00

62 lines
2.2 KiB
JavaScript

// Sync-policy constants: one source of truth for every enforcement point on both
// sides of a sync.
// The ONLY global _sc_config keys a deployer syncs. The capture side records /
// ships only these and the apply side refuses any other key, so a compromised
// peer cannot write security-relevant config it was never meant to touch
// (disable_csrf_routes, custom HTML headers, SMTP creds). Per-environment
// settings (base_url: links, OAuth callbacks, the idp issuer) are deliberately
// absent.
const SYNCABLE_CONFIG_KEYS = [
"menu_items",
"site_name",
"site_logo_id"
];
// User tables that must NEVER receive peer-synced rows and must never be
// flipped into managed/starter mode, no matter what a peer sends. `users` is the
// crown jewel: a synced row there is an injected account (role_id=1 => admin
// takeover). Enforced on the apply (and revert) side, not just the UI, since a
// hostile authenticated peer never goes through the UI.
const ROW_SYNC_LOCKED_TABLES = ["users"];
// Per-table row-propagation modes.
// user (default) -- rows belong to the target; sync never touches them.
// starter -- rows ship once (initial seed), then the target owns them.
// managed -- rows always converge from source; source is canonical.
const DATA_MODES = {
USER: "user",
STARTER: "starter",
MANAGED: "managed"
};
// Plugin/system infrastructure: a table OR field whose name
// begins with "_" is reserved by Saltcorn (_sc_*) and plugins (_dd_*, _ss_*,
// _idp_*, the per-row identity columns _dd_row_uuid / _ss_row_uuid). Infra is
// never journaled, synced, diffed, pruned, or offered a data mode. (Documented
// limitation: an application table or field named with a leading underscore is
// not synced.)
const isInfraName = (name) => {
return typeof name === "string" && name.startsWith("_");
};
const isLockedTable = (name) => {
return ROW_SYNC_LOCKED_TABLES.includes(name);
};
const isSyncedMode = (mode) => {
return mode === DATA_MODES.MANAGED || mode === DATA_MODES.STARTER;
};
module.exports = {
SYNCABLE_CONFIG_KEYS,
ROW_SYNC_LOCKED_TABLES,
DATA_MODES,
isInfraName,
isLockedTable,
isSyncedMode
};