Перейти до вмісту

Блог ·

Ярлик є посиланням, а не правом

Шість карток, які можна додати на панель, і ярлики, що показуються лише тоді, коли глядач ще має право бачити ціль сьогодні. Дві знахідки дала жива проба.

Автор: Provibr

Головна панель хостингового кабінету є екраном, який кожен бачить першим і про який майже ніхто не має думки, доки він не складений для нього хибно. Прохання було скромним: дати людям додавати картки і дати їм ставити ярлики на сервер чи інтеграцію, до яких вони вертаються знову й знову.

Скромні прохання є місцем, де ховаються цікаві рішення, бо ярлик є збереженим уподобанням, що вказує на справжній обʼєкт зі справжніми правами. Викривити це співвідношення означає дійти до кабінету, який показує комусь машину, від якої його відсторонили три місяці тому.

Шість карток, жодної міграції, і ніщо не приходить без прохання

Карток, які можна додати, шість: список агентів, список серверів, список інтеграцій, список звернень, залишок коштів і ярлик. Усі шість мають половинну ширину, бо це огляди поруч, а не щось, що потребує цілого рядка.

Розкладка зберігається як JSON, і цей раунд не додав жодної міграції. Це рішення, а не забудькуватість. Запис становив ідентифікатор і ознаку прихованості; тепер він несе ще й ідентифікатор примірника та налаштування для кожної картки. Старий рядок чисто читається в нову форму, з ідентифікатором примірника, доповненим з ідентифікатора картки, і порожнім налаштуванням, і тест перевіряє саме це: стара розкладка читається як ті самі картки в тому самому порядку. Міграція тут поставила б лише позначку часу в журнал, а позначка часу, яка згодом виявиться завеликою, є справжньою бідою для наступного раунду.

Друге правило полягає в тому, що необовʼязкова картка ніколи не зʼявляється сама. Є цикл, який додає картки, яких розкладка не називає, щоб нова стала картка зʼявилася в усіх, і цей цикл навмисно охоплює лише сталі картки. Якби до нього потрапила необовʼязкова, «додати» перестало б бути дією, і кожна панель у продукті росла б із кожним випуском на картку, якої ніхто не просив.

Яких карток бракує, є рішенням так само, як і те, які є. Спостереження і резервні копії існують у коді за вимкненими прапорцями розгортання, тож картка для них була б карткою без користувачів. Недавня діяльність лишилася назовні, бо вона вже існує як стала картка.

Дві половини одного правила

У збереженій розкладці особи ярлик є не чим іншим, як родом та ідентифікатором. Усе, що потрапляє на екран, назва, стан, посилання, добувають знову за кожного завантаження сторінки з правами того, хто дивиться тієї миті. Це правило має дві половини, і потрібні обидві.

Перша є модулем. Учасник, який утрачає модуль агентів, перестає бачити свій ярлик на агента, навіть якщо той лишається в його розкладці. Ця брама знає ще й поверхні: на власному марочному домені клієнта, де виставлення рахунків узагалі не існує, ярлик на залишок коштів зникає за побудовою, а не через друге правило, написане навмисно.

Друга є запитом на обʼєкт. Ідентифікатор організації стоїть у кожному WHERE, поруч фільтр мʼякого вилучення, а для сервера поруч ще й обсяг серверів того учасника. Сервер, якого учасникові ніколи не призначали, для нього не існує, і це має справджуватися і для ярлика, який він зробив тоді, коли ще мав право його бачити.

Картка ярлика є також єдиною карткою без модуля і єдиною, якій дозволено існувати кілька разів. Це слушно, а не недбало: ярлик не є власним екраном, він є посиланням на екран, який власне право вже несе. Якби рід картки ніс модуль, глядач із цим модулем міг би побачити ярлик на щось, чого відкрити не має права.

Модуль забрано і обʼєкт зник становлять різні події

Дві речі, які на екрані мають однаковий вигляд, дістають протилежне поводження.

Що сталосяЩо бачить глядач
Модуль забраноКартка зникає без жодного слова і вертається разом із модулем
Ціль не знайденоКартка, яка каже, що її вже немає, з кнопкою прибрати

Перше мовчазне, бо ярлик не є історією. Якщо роль когось змінилася, відсутній ярлик є симптомом, і оголошувати його на панелі означало б шум поверх зміни, яку він і так знає. До того ж він вертається неушкодженим, щойно вертається модуль, а це можливо лише тому, що нічого не вилучено.

Друге гучне, бо особа нічого хибного не зробила, а в неї щось забрали. Це навмисно не 404 і не повідомлення про помилку: просто картка, яка називає становище і пропонує прибрати себе.

Поблажливе показування, а не прибирання під час вилучення

Очевидна заміна полягає в тому, щоб прибирати ярлики, коли їхню ціль вилучають. Ми цього не зробили, і міркування варте запису, бо протилежне рішення в тій самій базі коду таки ухвалене: коли учасник полишає обліковий запис, його збережена розкладка справді забувається, бо той рядок не чіпає жодного каскаду і лишався б інакше назавжди в обліковому записі, куди він ніколи не вертається.

Тут терези хиляться в інший бік, із трьох причин.

Зникнення має більше причин, ніж вилучення. Учасник утрачає модуль, його обсяг серверів змінюється, він дивиться на марочному домені. Жодна процедура прибирання не ловить ці три випадки, тож поблажливий шлях має існувати однаково, а другий засіб стає лише ще одним місцем, яке може розійтися.

Розкладка зберігається для кожної особи. Один вилучений сервер змусив би переписати JSON кожного учасника організації, у транзакції на шляху вилучення. Це підсилення запису на гарячому шляху в обмін на екранне вподобання.

І захищати немає чого. Збережений рядок є UUID обʼєкта власної організації і нічим більше. Він нічого не виказує, не росте, і особа одразу бачить, що він може піти.

Наскрізна проба навмисно груба. Після мʼякого вилучення сервер не вертається, і його назви немає ніде у виведенні. Учасник без модуля агентів не дістає ні агента, ні інтеграції, і вибирач їх не пропонує. Порожній обсяг серверів дає нуль рядків, а не все.

Дві знахідки, які дала лише жива проба

Обидві справжні вади цього раунду були невидимі для одиничних тестів, і обидві коштували десь десять секунд, щойно щось справжнє запрацювало.

Вибирач має поле пошуку, і пошук інтеграцій ламав увесь вибирач помилкою бази даних. Причина полягає в тому, що стовпець із типом інтеграції є перелічуваним типом Postgres, а для переліку немає взірцевого оператора, байдужого до регістру: запит повернув 42883 operator does not exist, і оскільки той запит живив увесь вибирач, не показувалося геть нічого. Перетворення стовпця на текст це лагодить. Жоден одиничний тест зі змодельованим виконавцем цього не побачив би, бо модель не має типів.

Друга вийшла з обходу доступності. Плитка ярлика є назвою, станом і родом, і все разом можна натиснути. Перша версія клала все це в одне посилання, і перевірка вказала на розбіжність між доступною назвою і видимим підписом, бо прихований текст зараховується до доступної назви. Плитка тепер є звичайною оболонкою з посиланням, яке несе тільки назву, і порожньою абсолютною площею натискання, що ловить клік. Це принесло другу, меншу біду: клас обрізання на посиланні обрізав ту площу до ширини тексту, тож більша частина плитки перестала натискатися. Обрізання переїхало на внутрішній елемент, а покриття виміряли замість припускати.

Що б ми записали

  1. Зберігати посилання, розвʼязувати право. В уподобання йде ідентифікатор. Те, що потрапляє на екран, добувають щоразу з правами того, хто дивиться.
  2. Стовпець без схеми є міграцією, якої не треба писати. Але лише коли ви можете довести, що стара форма перечитується однаково, а це тест.
  3. Необовʼязкове означає на прохання, назавжди. Картка, яка зʼявляється сама, робить із «додати» слово без змісту.
  4. Розрізняти вилучене і недосяжне. На екрані вони однакові й заслуговують на протилежне поводження: тишу для одного, пояснення для іншого.
  5. Не прибирати може бути сильнішим вибором. Якщо той самий симптом має причини, яких ваше прибирання не бачить, поблажливий шлях має існувати однаково, а прибирання стає лише другою річчю, яку треба тримати в лад.
  6. Запустити цю річ. Перелік без взірцевого оператора і посилання, що обрізає власну площу натискання, обидва видно за мить у браузері й обох геть не видно в наборі тестів без бази даних.

Для ясності щодо того, чим це є: описані тут картки працюють у продуктиві для кожного облікового запису. Кілька речей лишилися недоведеними. Перевпорядкування мишею не вели, карток спостереження і резервних копій за прапорцем немає, тож їхнім шляхом коду ніколи не проходили, марочний домен перевірили в запиті, а не в браузері, і щойно додана картка зʼявляється лише після наступного обходу сервера.

Із платформної роботи Provibr. Що клієнт нашого клієнта бачить і чого не бачить у марочному кабінеті, описано в кабінети під власною маркою: що бачить клієнт, а чому зведений екран ніколи не пише назад у таблиці, які читає, описано в проєктувати, ніколи не заміняти.

Читати далі

Почніть з одного хоста й одного агента

Створіть обліковий запис, встановіть агента однією командою та підключіть свій перший хост Proxmox. Пробний період триває 14 днів і не потребує платіжних даних.