Merge pull request 'fix(demo): refuse publishing the homepage hero (DM21)' (#225) from fix/demo-hero-publish-lock into main
Some checks failed
sync-project-tree / sync (push) Successful in 25s
Build container images / build (push) Successful in -13s
Build container images / deploy (push) Successful in 47s
SonarQube / analysis (push) Failing after 6m25s

Reviewed-on: #225
Reviewed-by: Colby Whitlock <whitlocktech@gmail.com>
This commit is contained in:
2026-10-26 14:50:55 +00:00
2 changed files with 16 additions and 2 deletions

View File

@@ -65,8 +65,10 @@ async function callerIsDemo(req) {
// keys, and a few keys are another door into something Tier A locks: `site_mode`
// is what `PUT /admin/site-mode` writes, `module_source_hosts` what the Modules
// screen's sources do, `teams_voice_*` the voice settings. `demo_*` is the
// banner and the published logins, which the seed owns.
const PROTECTED_SETTINGS = [/^site_mode/, /^module_source_hosts$/, /^teams_voice_/, /^demo_/]
// banner and the published logins, which the seed owns. `hero_layout` is the
// live homepage hero (DM21): the editor's draft (`hero_layout_draft`) and its
// Preview stay open, its Publish is refused.
const PROTECTED_SETTINGS = [/^site_mode/, /^module_source_hosts$/, /^teams_voice_/, /^demo_/, /^hero_layout$/]
function protectedKeys(body) {
if (!body || typeof body !== 'object' || Array.isArray(body)) return []

View File

@@ -184,6 +184,18 @@ test('PUT /admin/settings is open for theme and nav', async () => {
})
})
// DM21: the hero editor's autosave and Preview write only the draft; Publish
// writes both, and the live key refuses the whole body.
test('the hero draft is open, publishing the hero is refused', async () => {
await withLock(undefined, async (req) => {
await expectReached(await req('PUT', '/admin/settings', { hero_layout_draft: '{"v":1}' }))
const body = await expectLocked(
await req('PUT', '/admin/settings', { hero_layout: '{"v":1}', hero_layout_draft: '{"v":1}' }),
)
assert.deepEqual(body.keys, ['hero_layout'])
})
})
test('PUT /admin/settings naming a protected key is refused whole, with the keys named', async () => {
await withLock(undefined, async (req) => {
for (const key of ['site_mode', 'site_mode_changed_by', 'module_source_hosts', 'teams_voice_enabled', 'demo_state']) {