Zum Hauptinhalt springen

Blueprint-Eigentum: Was ein Update behält

Ein Blueprint-Update importiert die Seed-Daten erneut in einen Tenant, der eine Weile in Benutzung war. Der Import ersetzt jede berührte Entität vollständig. Ohne Regeln würde ein Seed mit einem leeren Wert daher löschen, was der Tenant seit der Installation eingetragen hat (eine Adapter-Konfiguration, einen Enforcement-Modus, einen Zähler, einen Mailtext). Die Regeln auf dieser Seite legen für jeden Wert fest, ob der Blueprint oder der Tenant ihn besitzt, und was die Plattform tut, wenn beide nicht übereinstimmen.

Es gibt vier Schichten. Jede ist unabhängig; ein Wert wird nur ersetzt, wenn keine von ihnen ihn schützt.

SchichtFrageEntschieden durch
Eigentum an der Seed-EntitätGehört dem Tenant die ganze Entität?rtBlueprintLocked im Seed
Attribut-OwnershipGehört dem Tenant dieses Attribut?ownership im CK-Modell
Blanking-GuardWürde das Seed einen gefüllten Wert leeren?Die Engine, für jedes SeedOwned-Attribut
Vorschau und BestätigungWas würde das Update behalten oder leeren, und stimmt der Operator zu?PreviewBlueprintUpdate, UpdateBlueprint

Ein weiterer Schalter, ProtectBlueprintLocked, betrifft nicht Updates, sondern Benutzer: Er macht die Entitäten, die ein Blueprint besitzt, für sie schreibgeschützt.

Welche Attribute jeder Plattform- und App-Blueprint schreibt und wem sie jeweils gehören, steht im Seed-Ownership-Audit und in dessen vollständiger Tabelle.

Die vier Ownership-Werte​

Jedes CK-Attribut deklariert mit ownership, wem sein Wert gehört. Die Ownership wird pro Attributzuweisung aufgelöst: Eine Überschreibung an der Zuweisung des Typs gewinnt gegen die Attributdefinition, und ein Attribut ohne Deklaration ist SeedOwned. (isRuntimeState: true ist die veraltete Schreibweise von RuntimeState.)

ownershipWem der Wert gehörtFrische InstallationBlueprint-Update oder erzwungenes erneutes AnwendenExportRt
SeedOwned (Standard)Dem Produkt. Der Blueprint-Autor liefert ihn aus, eine neue Version darf ihn korrigieren.Seed-Wert wird übernommenSeed-Wert ersetzt den gespeicherten Wert, außer der Blanking-Guard behält einen gefüllten Wert, wenn das Seed leer istExportiert
TenantOwnedDem Tenant. Ein Administrator oder Benutzer setzt ihn im Produkt.Seed-Wert initialisiert ihnGespeicherter Wert bleibt; das Seed initialisiert nur eine neue EntitätExportiert
RuntimeStateEin Dienst, ein Operator oder eine Pipeline schreibt ihn zur Laufzeit.Seed-Wert initialisiert ihnGespeicherter Wert bleibtAusgelassen
SecretZugangsdaten. Immer die Ownership des Werttyps Secret.Seed-Wert initialisiert ihn (ein Secret-Werttyp ist im Seed leer)Gespeicherter Wert bleibtNie exportiert
attributes:
- id: PolicyEnforcementMode
valueType: Enum
valueCkEnumId: ${this}/DataPolicyEnforcementMode
ownership: TenantOwned

Beispiele aus den Plattformmodellen: System.Identity/DataPolicy PolicyEnforcementMode und PolicyScope sind TenantOwned (ein Administrator, der eine Policy auf Enforce gestellt hat, behält Enforce); System.Communication/Adapter.AdapterConfiguration ist Secret (die Verbindungseinstellungen eines Adapters, die ein Passwort enthalten können, überstehen ein Update und wandern nie in eine Exportdatei); System.StreamData Archive.Status ist RuntimeState.

Prüffrage für jedes neue oder geänderte Attribut: Könnte ein Operator oder Benutzer diesen Wert im Produkt eintippen? Wenn ja, ist er TenantOwned (oder Secret für Zugangsdaten); wenn ein Dienst ihn schreibt, RuntimeState; nur ein Wert, den das Produkt ausliefert und korrigieren können muss, ist SeedOwned. Die Änderung der Ownership eines bestehenden Attributs ist eine Minor-Erhöhung der Modellversion.

Die Gegenrichtung

RuntimeState und TenantOwned schützen einen Tenant-Wert, und derselbe Schutz hindert einen Blueprint daran, ihn zu korrigieren. Eine Seed-Korrektur eines solchen Werts erreicht einen frischen Tenant und keinen bestehenden Tenant. Zwei Fälle sind gewollt:

  • Adapter.ChartVersion (und die übrigen Deployment-Werte eines Workloads) sind RuntimeState: Der Operator oder die CD-Pipeline setzt sie.
  • Die Redirect- und CORS-URIs eines Identity-Client sind RuntimeState: Der Tenant oder ein Overlay fügt sie hinzu.

Ein korrigierter Wert in einem von beiden muss durch einen CK-Migrationsschritt oder einen dokumentierten manuellen Schritt in die bestehenden Tenants geschrieben werden, nicht durch ein neues Seed.

Tenant-eigene Seed-Entitäten​

Das Flag rtBlueprintLocked im Seed legt fest, wem eine Entität gehört, sobald sie im Tenant existiert:

Seed sagtEigentümerErste InstallationUpdate, Tenant hat sieUpdate, Tenant hat sie nicht
Flag fehlt oder true (Standard)Produktangelegtaus dem Seed erneuert (Merge, Full)erneut angelegt (eine gelöschte Entität kommt zurück)
rtBlueprintLocked: falseTenantmit den Seed-Werten angelegtnicht angefasst, kein Konflikt (nur der Blueprint-Stempel wandert)nur angelegt, wenn sie neu ist; bleibt gelöscht, wenn das Seed der Vorgängerversion sie schon enthielt
entities:
- rtId: 65f1c0a2b3d4e5f601234567
ckTypeId: MyModel/MailTemplate
rtWellKnownName: DefaultTemplate
rtBlueprintLocked: false # einmal angelegt, danach Eigentum des Tenants
attributes:
- id: Name
value: Default template

Verwenden Sie das für Vorgaben, die ein Tenant bearbeiten oder entfernen soll (Vorlagen, Beispielregeln). Halten Sie die Entitäten, die das Produkt braucht, etwa die Regeln, von denen ein Feature abhängt, gesperrt. Vorschau und Update-Ergebnis listen die Entitäten in TenantOwnedSkipped (behalten) und TenantOwnedStaysDeleted (nicht zurückgebracht); siehe unten, wo Sie diese Listen lesen. Ein Tenant, der noch den Stempel rtBlueprintLocked: true einer früheren Version trägt, wird ab dem ersten Update, dessen Seed die Entität als entsperrt deklariert, als tenant-eigen behandelt. ImportRt -r kennt keine Blueprints und folgt dieser Regel nicht; wenden Sie ein Seed mit UpdateBlueprint oder InstallBlueprint an.

Der Blanking-Guard​

Die Attribut-Ownership schützt nur, was ein Modellautor markiert hat. Für alles andere (SeedOwned, der Standard) entscheidet die Engine pro Attribut bei jedem Upsert-Import (Blueprint-Installation, Update, erzwungenes erneutes Anwenden, ImportRt -r):

Gespeicherter WertSeedErgebnis
keiner oder leerbeliebigSeed-Wert wird übernommen
gefülltanderer, gefüllter WertSeed gewinnt (eine Korrektur des Blueprints, wie bisher)
gefülltleerer Wert (null, "", leere Liste, Record aus leeren Mitgliedern)gespeicherter Wert bleibt, wird gemeldet
gefülltAttribut fehlt, kein CK-Standardwertgespeicherter Wert bleibt, wird gemeldet
gefüllt und vom CK-Standardwert verschiedenAttribut fehlt, Attribut hat einen CK-Standardwertgespeicherter Wert bleibt, wird als ResetToDefault gemeldet
JSON-Text mit gefülltem StringJSON-Text mit leerem String an derselben Stellegespeicherter Wert bleibt als Ganzes, wird gemeldet (das leere Skelett einer Adapter-Konfiguration)

„Leer" ist bewusst eng gefasst: Zahlen, Booleans, Enums, Datumswerte und Zeitspannen sind nie leer, ein ausdrückliches 0, false oder das erste Enum-Mitglied im Seed ist also ein vom Autor gewählter Wert und ersetzt den Wert des Tenants. Records werden als Einheit behalten oder ersetzt.

Der Guard ist ein Sicherheitsnetz, kein Freibrief: Ein Wert, den ein Tenant eintippt, gehört im Modell zu TenantOwned oder Secret. Der Guard kann einen vom Tenant eingegebenen Wert nicht von einem Seed-Wert unterscheiden, den eine neue Version leeren möchte, und leert deshalb nie stillschweigend; siehe nächster Abschnitt.

Vorschau und explizite Bestätigung​

PreviewBlueprintUpdate führt dieselbe Erkennung wie das Update aus und listet jedes Attribut, dessen gefüllten Wert das Seed leeren würde, ohne Werte (sie können Zugangsdaten sein): Entitäts-ID, Typ, Attribut, Grund (SeedEmpty, SeedOmitted, ResetToDefault; die CLI gibt den Grund so aus, wie der Dienst ihn meldet) sowie eine Art-und-Größe-Angabe des aktuellen und des eingehenden Werts, zum Beispiel string (223 chars) gegen empty string.

# Die Liste lesen. Das JSON-Ergebnis geht auf die Standardausgabe, die Tabelle ins Log.
octo-cli -c PreviewBlueprintUpdate -tv MyBlueprint-2.0.0

# CI-Gate: Exit-Code -5, wenn etwas geleert würde
octo-cli -c PreviewBlueprintUpdate -tv MyBlueprint-2.0.0 -fb

# Standard-Update: Tenant-Werte, die das Seed leeren würde, werden BEHALTEN und aufgelistet, Exit-Code 0
octo-cli -c UpdateBlueprint -tv MyBlueprint-2.0.0

# Genau diese Attribute leeren (wiederholbar): <rtId>:<attribute> wie in der Vorschau
octo-cli -c UpdateBlueprint -tv MyBlueprint-2.0.0 -cb 65a1b2c3d4e5f60718293a4b:configuration

# ALLE aufgelisteten Attribute leeren (laute Warnung; bevorzugen Sie -cb)
octo-cli -c UpdateBlueprint -tv MyBlueprint-2.0.0 -ab
KurzLangAnBedeutung
-fb--failOnBlankingPreviewBlueprintUpdateMit Exit-Code -5 beenden, wenn das Update mindestens einen Tenant-Wert leeren würde
-cb--confirm-blankingUpdateBlueprintEin Attribut bestätigen, <rtId>:<attribute>; die Option für mehrere wiederholen. Alles Unbestätigte bleibt erhalten
-ab--allow-blankingUpdateBlueprintJedes aufgelistete Attribut bestätigen; hat Vorrang vor -cb

Die vollständigen Optionslisten stehen in der Befehlsreferenz zu PreviewBlueprintUpdate und UpdateBlueprint. Die REST-API trägt denselben Vertrag: POST {tenantId}/v1/blueprints/updates/preview liefert blankedAttributes, und POST {tenantId}/v1/blueprints/updates/apply akzeptiert allowBlanking und confirmedBlankings ([{ rtId, attributeName }]) und antwortet wieder mit der Liste, in der appliedOnUpdate für einen behaltenen Wert false und für einen auf Bestätigung geleerten true ist. Nichts geschieht still.

Was Sie mit der Liste tun. Entscheiden Sie für jede Zeile, wer recht hat. Ein Wert, den der Tenant eingegeben hat und den das Produkt nicht anfassen soll: nichts tun (das Update behält ihn) und das Attribut als Modellproblem melden, denn es sollte TenantOwned sein. Ein Wert, den das Produkt wirklich entfernen will: mit -cb bestätigen. Studio wendet Updates und erneutes Anwenden mit dem Standard an und leert deshalb nie; es zeigt die Liste noch nicht an, verwenden Sie vor einem Update auf einem Tenant mit eingegebenen Daten PreviewBlueprintUpdate.

Vorschau und Guard sind nur so gut wie der Dienst, der sie ausführt: Ein Dienst, der älter als das Feature ist, meldet keine Liste und verhält sich wie zuvor (siehe Verfügbarkeit).

Wo Betreiber übersprungene und gelöscht bleibende Entitäten sehen​

Ein Update lässt tenant-eigene Seed-Entitäten bewusst in Ruhe. Damit das sichtbar ist und kein stilles Auslassen, listen Vorschau und Update-Ergebnis sie auf, in REST, GraphQL, im SDK und in octo-cli. Sie sind kein Blanking: blankedAttributes, -cb, -ab und -fb beachten sie nicht.

ListeBedeutungentityId
tenantOwnedSkippedDer Tenant hält die Entität noch; das Update hat sie unberührt gelassenLaufzeit-ID auf dem Tenant
tenantOwnedStaysDeletedDas vorherige Seed enthielt sie, der Tenant hat sie gelöscht, das Update bringt sie nicht zurücknull

Jeder Eintrag trägt key (der rtWellKnownName der Seed-Entität, sonst ihre rtId), ckTypeId, entityId und wellKnownName. Nur Identität, nie Attributwerte: eine tenant-eigene Entität kann Zugangsdaten enthalten. Beide Listen werden in entitiesSkipped mitgezählt und sind leer, wenn es nichts zu melden gibt; ein Client, der sie ignoriert, verhält sich wie zuvor.

OberflächeWo
RESTPOST {tenantId}/v1/blueprints/updates/preview (tenantOwnedSkipped, tenantOwnedStaysDeleted im JSON-Body) und POST {tenantId}/v1/blueprints/updates/apply (dieselben Member im Ergebnis)
GraphQLblueprints.previewUpdate { tenantOwnedSkipped { key ckTypeId entityId wellKnownName } tenantOwnedStaysDeleted { ... } } und dieselben Felder am Ergebnis von applyUpdate (BlueprintApplyResult, bei einer Installation leer)
SDKBlueprintUpdatePreviewDto und BlueprintUpdateResultDto: TenantOwnedSkipped, TenantOwnedStaysDeleted (BlueprintTenantOwnedEntityDto)
octo-cliPreviewBlueprintUpdate und UpdateBlueprint protokollieren eine Tabelle „tenant-owned, skipped“ und eine „deleted by the tenant, stays deleted“ (Schlüssel, Typ, rtId, - bei einer gelöschten Entität); bei leeren Listen wird nichts ausgegeben
1 tenant-owned seed entity(ies) would be left untouched (tenant-owned, skipped):
Key Type Entity (rtId)
OwnedKept Test/Rule 65a1b2c3d4e5f60718293a4b
1 tenant-owned seed entity(ies) deleted by the tenant would stay deleted:
Key Type Entity (rtId)
OwnedGone Test/Rule -

Der Installationspfad meldet den Umgang mit tenant-eigenen Entitäten nur in seinen Operationsmeldungen, ohne diese Listen.

Was ein Blueprint-Autor tut, um einen tenant-eigenen Wert zu ändern​

Ein Seed kann einen Wert, den der Tenant besitzt, nicht ändern und einen gefüllten nicht leeren. Das ist gewolltes Verhalten. Muss eine neue Version einen solchen Wert in bestehenden Tenants wirklich ändern, wählen Sie eines davon:

  1. Ein CK-Migrationsschritt des Modells (Update-Aktion auf den Entitäten, siehe CK-Modell-Migrationen) oder ein Blueprint-Migrationsskript (UpdateBlueprint -m Migration, siehe Blueprints). Die Änderung ist explizit, versioniert und prüfbar.
  2. Ein dokumentierter manueller Schritt für den Operator, mit dem genauen zu setzenden Wert, wenn die Änderung von der Umgebung abhängt.
  3. Die explizite Blanking-Bestätigung (-cb), nur wenn die Absicht ist, einen Wert zu leeren; einen neuen Wert kann sie nicht schreiben.
  4. Die Ownership korrigieren, wenn das Attribut falsch eingestuft war: Ein Attribut, das ein Tenant eintippt, ist TenantOwned oder Secret, ein Attribut, das das Produkt korrigieren können muss, ist SeedOwned. Eine Ownership-Änderung ist eine Minor-Erhöhung des CK-Modells und wirkt für einen Tenant, sobald er die neue Modellversion importiert hat.

Umgehen Sie die Regeln nicht, indem Sie den Wert in einer zweiten Seed-Entität ausliefern oder sich auf ein erzwungenes erneutes Anwenden verlassen: Ein erzwungenes erneutes Anwenden folgt genau denselben Regeln wie ein Update.

Blueprint-gesperrte Entitäten vor Benutzern schützen​

rtBlueprintLocked allein steuert nur Updates; ein Benutzer kann eine gesperrte Entität weiterhin bearbeiten. Ein Blueprint kann die Entitäten, die er besitzt, für Benutzer schreibgeschützt machen, indem er für den Typ eine System.Identity/DataPolicy mit ProtectBlueprintLocked: true ausliefert. Verhalten, der Fehler BLUEPRINT_LOCKED (Meldung 6384) und die abgedeckten Pfade sind unter Blueprints beschrieben. Was ein Blueprint-Autor beachten muss:

  • Untergrenze. Heben Sie die CK-Abhängigkeit des Blueprints auf System.Identity-[2.24.0,3.0) an. Ein älteres System.Identity verwirft das Attribut stillschweigend.
  • Das Flag ist SeedOwned. Jedes Update und jedes erzwungene erneute Anwenden setzt den ausgelieferten Wert wieder ein; Benutzer können den Schutz nicht dauerhaft abschalten, und eine spätere Version kann ihn verschärfen oder lockern.
  • Liefern Sie ein explizites false aus, um einen Schutz zurückzunehmen. Ein Seed, das das Attribut nur weglässt, behält ein gespeichertes true, weil der Blanking-Guard den gefüllten Wert behält.
  • Eine Policy pro geschütztem Typ, in einer eigenen Policy-Gruppe. Die Policy ist eine Einschränkung, keine Berechtigung: Geben Sie den Rollen, die mit dem Typ arbeiten, ihre PolicyPermission.
  • Entitäten, die der Tenant besitzen soll, bleiben mit rtBlueprintLocked: false im Seed bearbeitbar.

Verfügbarkeit​

Die Schutzmaßnahmen kamen schrittweise. Das erste Plattform-Release, das sie enthält:

SchutzPlattform-ReleaseVoraussetzung
Attribut-Ownership TenantOwned, RuntimeState, Secretfrühere Releasesdas CK-Modell des Attributs trägt die Markierung
Adapter-Konfiguration ist Secret3.5.7System.Communication 4.7.0 im Tenant importiert
DataPolicy-Modus und -Scope, Schalter von Client und ApiResource sind TenantOwned3.5.7System.Identity 2.23.0 im Tenant importiert
Blanking-Guard3.5.3
Update-Vorschau, blankedAttributes3.5.5Dienst und octo-cli
tenantOwnedSkipped / tenantOwnedStaysDeleted in Vorschau und Ergebnis (REST, GraphQL, SDK, octo-cli)die Version nach 3.5.9, die AB#6454 enthältDienst, octo-sdk und octo-cli
-fb, -cb, -ab3.5.5octo-cli
Tenant-eigene Seed-Entitäten (rtBlueprintLocked: false)3.5.8
ImportRt beachtet die Blueprint-Sperre3.5.9ProtectBlueprintLocked-Policy
ProtectBlueprintLockedmit System.Identity 2.24.0die Untergrenze des Blueprints

Eine Ownership-Markierung wirkt für einen Tenant, wenn der Tenant die Version des CK-Modells importiert hat, die sie trägt; der Dienst importiert seine eingebetteten System-Modelle, wenn ein Tenant aufgelöst wird. Prüfen Sie die Modellversion eines Tenants, bevor Sie sich auf eine Markierung verlassen.

Siehe auch​