UIAP Policy Extension
UIAP Policy Extension v0.1
Abschnitt betitelt „UIAP Policy Extension v0.1“| Feld | Wert |
|---|---|
| Status | Draft |
| Version | 0.1 |
| Datum | 2026-03-27 |
| Abhängigkeiten | [UIAP-CORE] |
| Editoren | Patrick |
1. Zweck
Abschnitt betitelt „1. Zweck“UIAP Policy Extension v0.1 definiert, wie eine Anwendung Regeln für:
- erlaubte Agent-Aktionen,
- Bestätigungen,
- sensible Daten,
- Redaktion,
- Audit,
- Human Handoff
maschinenlesbar beschreibt und zur Laufzeit auswertet.
Die Extension baut auf UIAP Core v0.1, Capability Model v0.1, Web Profile v0.1 und Action Runtime v0.1 auf.
Normative Begriffe
Abschnitt betitelt „Normative Begriffe“Die Schlüsselwörter MUSS, DARF NICHT, SOLLTE, KANN in diesem Dokument sind normativ gemäss RFC 2119 und BCP 14 zu interpretieren, wenn und nur wenn sie in GROSSBUCHSTABEN erscheinen.
2. Kennung und Aushandlung
Abschnitt betitelt „2. Kennung und Aushandlung“type ExtensionId = "uicp.policy";type ExtensionVersion = "0.1";Eine Implementierung, die diese Erweiterung nutzt, MUSS sie im Handshake aushandeln:
{ "id": "uicp.policy", "versions": ["0.1"], "required": false}3. Geltung und Grundsätze
Abschnitt betitelt „3. Geltung und Grundsätze“- Policy ist lokal durchsetzbar. Eine App oder Bridge MUSS eine Policy-Entscheidung auch dann durchsetzen können, wenn der Agent etwas anderes will.
- Policy ist entscheidungsorientiert, nicht promptorientiert.
- Policy trennt Berechtigung, Risiko, Sensitivität, Audit-Pflicht und Handoff-Pflicht.
- Policy MUSS vor jeder nicht-trivialen Action ausgewertet werden.
- Policy DARF nie schwächer sein als Browser- oder Plattformgrenzen.
4. Kernbegriffe
Abschnitt betitelt „4. Kernbegriffe“4.1 Principals
Abschnitt betitelt „4.1 Principals“type PrincipalType = "user" | "agent" | "bridge" | "observer" | "system";
interface PolicyPrincipal { type: PrincipalType; id: string; roles?: string[]; grants?: PolicyGrant[];}4.2 Grants
Abschnitt betitelt „4.2 Grants“type PolicyGrant = | "observe" | "guide" | "draft" | "act" | "admin" | "read.sensitive" | "read.secret" | "write.sensitive" | "billing" | "identity" | "security";Semantik
Abschnitt betitelt „Semantik“observe: UI lesen, aber nichts verändernguide: Highlight/Fokus/Navigation ohne Seiteneffektdraft: reversible Entwürfe oder Feldvorschlägeact: normale operative Actionsadmin: privilegierte Actions- zusätzliche Grants regeln sensible Domänen und Daten
4.3 Datenklassen
Abschnitt betitelt „4.3 Datenklassen“type DataClass = | "public" | "internal" | "personal" | "sensitive" | "credential" | "secret" | "payment" | "legal";4.4 Seiteneffektklassen
Abschnitt betitelt „4.4 Seiteneffektklassen“type SideEffectClass = | "none" | "local_ui" | "internal_persist" | "external_message" | "identity_change" | "billing_change" | "security_change" | "irreversible";4.5 Policy-Entscheidungen
Abschnitt betitelt „4.5 Policy-Entscheidungen“type PolicyEffect = | "allow" | "confirm" | "deny" | "handoff";4.6 Begründungscodes
Abschnitt betitelt „4.6 Begründungscodes“type PolicyReasonCode = | "grant_missing" | "route_denied" | "target_denied" | "risk_confirm" | "risk_blocked" | "sensitive_data" | "secret_data" | "credential_data" | "external_effect" | "privileged_action" | "user_activation_missing" | "human_actor_required" | "unsafe_retry" | "redaction_required" | "policy_default";5. Policy-Dokument
Abschnitt betitelt „5. Policy-Dokument“interface PolicyDocument { modelVersion: "0.1"; extension: "uicp.policy";
defaults: PolicyDefaults; rules: PolicyRule[];
redaction?: RedactionRule[]; audit?: AuditPolicy; handoff?: HandoffPolicy;
metadata?: Record<string, unknown>;}interface PolicyDefaults { onSafeRisk: PolicyEffect; // RECOMMENDED: "allow" onConfirmRisk: PolicyEffect; // RECOMMENDED: "confirm" onBlockedRisk: PolicyEffect; // RECOMMENDED: "handoff" onUnknownAction: PolicyEffect; // RECOMMENDED: "deny" onSensitiveRead: PolicyEffect; // RECOMMENDED: "confirm" onSecretRead: PolicyEffect; // RECOMMENDED: "deny"}5.1 Policy-Regeln
Abschnitt betitelt „5.1 Policy-Regeln“interface PolicyRule { id: string; enabled?: boolean; priority?: number; // higher wins
when: PolicyPredicate; effect: PolicyEffect;
obligations?: PolicyObligation[]; reason?: string;}interface PolicyPredicate { actionIds?: string[]; routeIds?: string[]; stableIds?: string[]; roles?: UIRole[];
riskLevels?: RiskLevel[]; riskTags?: RiskTag[];
dataClasses?: DataClass[]; sideEffectClasses?: SideEffectClass[];
principals?: string[]; // principal.id principalTypes?: PrincipalType[]; requiredGrants?: PolicyGrant[];
executionModes?: ExecutionMode[];}5.2 Obligations
Abschnitt betitelt „5.2 Obligations“type PolicyObligation = | { type: "audit"; level?: AuditLevel; } | { type: "redact"; paths: string[]; replacement?: string; } | { type: "limitExecutionModes"; modes: ExecutionMode[]; } | { type: "requireVerification"; policy: "any" | "all"; signals?: SuccessSignal[]; } | { type: "requireUserActivation"; } | { type: "requireHumanActor"; reason?: string; } | { type: "maxAttempts"; value: number; };6. Policy-Kontext
Abschnitt betitelt „6. Policy-Kontext“interface PolicyContext { sessionId?: string; revision?: RevisionId;
principal: PolicyPrincipal;
actionId: ActionId; target?: { ref?: TargetRef; stableId?: StableId; role?: UIRole; name?: string; scopeId?: ScopeId; documentId?: DocumentId; };
risk?: RiskDescriptor; dataClasses?: DataClass[]; sideEffectClass?: SideEffectClass;
executionMode?: ExecutionMode; routeId?: string;
userActivation?: { isActive?: boolean; hasBeenActive?: boolean; };
retryOfActionHandle?: string; attempt?: number;
args?: Record<string, unknown>; metadata?: Record<string, unknown>;}7. Policy-Entscheidung
Abschnitt betitelt „7. Policy-Entscheidung“interface PolicyDecision { decision: PolicyEffect; reasonCodes: PolicyReasonCode[];
obligations?: PolicyObligation[]; effectiveExecutionModes?: ExecutionMode[];
redactions?: RedactionPlan[]; audit?: AuditDirective;
cacheTtlMs?: number;}interface RedactionPlan { path: string; replacement: string;}type AuditLevel = "none" | "decision" | "result" | "full";
interface AuditDirective { level: AuditLevel; emitRecord: boolean;}8. Nachrichtentypen
Abschnitt betitelt „8. Nachrichtentypen“8.1 uicp.policy.get
Abschnitt betitelt „8.1 uicp.policy.get“Request
Abschnitt betitelt „Request“interface PolicyGetPayload {}Response: uicp.policy.document
Abschnitt betitelt „Response: uicp.policy.document“interface PolicyDocumentPayload { policy: PolicyDocument; revision?: string;}8.2 uicp.policy.evaluate
Abschnitt betitelt „8.2 uicp.policy.evaluate“Request
Abschnitt betitelt „Request“interface PolicyEvaluatePayload { context: PolicyContext;}Response: uicp.policy.decision
Abschnitt betitelt „Response: uicp.policy.decision“interface PolicyDecisionPayload { contextHash?: string; decision: PolicyDecision;}8.3 uicp.policy.changed
Abschnitt betitelt „8.3 uicp.policy.changed“interface PolicyChangedPayload { revision: string; reason?: "role_change" | "tenant_change" | "feature_flag" | "policy_update" | string; policy: PolicyDocument;}8.4 uicp.policy.audit
Abschnitt betitelt „8.4 uicp.policy.audit“interface PolicyAuditPayload { record: PolicyAuditRecord;}interface PolicyAuditRecord { auditId: string; ts: string; sessionId?: string;
principal: PolicyPrincipal; actionId?: ActionId; target?: TargetRef;
decision: PolicyEffect; reasonCodes: PolicyReasonCode[];
obligations?: PolicyObligation[]; sideEffectClass?: SideEffectClass;
outcome?: "preflight" | "granted" | "confirmed" | "executed" | "failed" | "denied" | "handoff"; stateRevision?: RevisionId;
metadata?: Record<string, unknown>;}9. Auswertungsreihenfolge
Abschnitt betitelt „9. Auswertungsreihenfolge“Ein Policy Executor MUSS Entscheidungen in dieser Reihenfolge ableiten:
- Explizite Deny-Regeln
- Grant-Prüfung
- Target-/Route-Blocklisten
- Datenklassen und Redaktionspflicht
- Risk Level und Risk Tags
- Seiteneffektklasse
- User-Activation-/Human-Actor-Pflichten
- Defaults
Empfohlene sichere Baseline
Abschnitt betitelt „Empfohlene sichere Baseline“safe+ ausreichende Grants →allowconfirm→confirmblocked→handoffsecret/credentiallesen ohne Spezialgrant →deny- nicht-idempotenter Retry bei
sideEffectState="unknown"→denyoderhandoff
10. Redaktionsmodell
Abschnitt betitelt „10. Redaktionsmodell“Redaktion MUSS getrennt von Action-Zulässigkeit modelliert werden.
interface RedactionRule { id: string; when: { dataClasses?: DataClass[]; stableIds?: StableId[]; routeIds?: string[]; }; applyTo: Array<"snapshot" | "signal" | "returnValue" | "audit">; replacement?: string; // default: "[REDACTED]"}- Redaktion DARF ein Objekt teilweise maskieren, ohne die Action selbst zu verbieten.
credentialundsecretSOLLTEN standardmäßig redaktiert werden.- Audit-Daten SOLLTEN stärker redaktiert werden als Laufzeitdaten.
11. Handoff-Modell
Abschnitt betitelt „11. Handoff-Modell“Browser und Plattform verlangen in manchen Fällen echte Nutzerinteraktion oder vertrauenswürdige Eingaben. Deshalb ist handoff kein Fehler, sondern ein normaler Policy-Ausgang. navigator.userActivation liefert den Aktivierungszustand, Event.isTrusted unterscheidet Browser-/User-Agent-generierte Events von dispatchEvent()-Events, und HTMLElement.click() ersetzt nicht automatisch jede user-activation-gated Situation. ([MDN Web Docs][2])
interface HandoffPolicy { triggers: HandoffTrigger[]; defaultMessage?: string;}type HandoffTrigger = | "user_activation_required" | "credential_entry" | "payment_approval" | "external_auth" | "captcha" | "legal_acknowledgement" | "ambiguity" | "security_sensitive";- Wenn eine Obligation
requireUserActivationenthält unduserActivation.isActive !== true, MUSS die Entscheidung mindestenshandoffsein. - Wenn
requireHumanActoraktiv ist, DARF keine autonome Ausführung folgen. handoffSOLLTE einen menschenlesbaren Grundtext erzeugen können.
12. Minimaler Konformitätsumfang
Abschnitt betitelt „12. Minimaler Konformitätsumfang“Eine konforme [email protected]-Implementierung MUSS:
uicp.policy.getunduicp.policy.evaluateunterstützen,PolicyDocumentundPolicyDecisionvalidieren,confirm,deny,handoffundallowunterscheiden,- Redaction Rules anwenden können,
- Audit-Records erzeugen können,
blockedRisk härter behandeln alsconfirm.
13. Beispiel-Policy
Abschnitt betitelt „13. Beispiel-Policy“{ "modelVersion": "0.1", "extension": "uicp.policy", "defaults": { "onSafeRisk": "allow", "onConfirmRisk": "confirm", "onBlockedRisk": "handoff", "onUnknownAction": "deny", "onSensitiveRead": "confirm", "onSecretRead": "deny" }, "rules": [ { "id": "deny-credentials", "priority": 100, "when": { "dataClasses": ["credential", "secret"] }, "effect": "deny", "obligations": [ { "type": "audit", "level": "decision" } ] }, { "id": "confirm-create-video", "priority": 50, "when": { "actionIds": ["video.create"] }, "effect": "confirm", "obligations": [ { "type": "requireVerification", "policy": "all", "signals": [ { "kind": "route.changed", "pattern": "/videos/:id" }, { "kind": "toast.contains", "text": "erstellt" } ] }, { "type": "audit", "level": "result" } ] } ], "redaction": [ { "id": "mask-secrets", "when": { "dataClasses": ["secret", "credential"] }, "applyTo": ["snapshot", "audit", "returnValue"], "replacement": "[REDACTED]" } ], "audit": { "level": "result", "includeArgs": false, "includeReturnValue": false }, "handoff": { "triggers": [ "user_activation_required", "credential_entry", "payment_approval", "external_auth" ], "defaultMessage": "Bitte übernimm diesen Schritt selbst." }}Normative Referenzen
Abschnitt betitelt „Normative Referenzen“- [UIAP-CORE] UIAP Core v0.1
- [RFC2119] Key words for use in RFCs to Indicate Requirement Levels, BCP 14
Security Considerations
Abschnitt betitelt „Security Considerations“- Policy-Dokumente SOLLTEN nur von vertrauenswürdigen Quellen geladen werden.
- Eine lokale
deny-Entscheidung MUSS immer Vorrang haben und DARF NICHT von einem externen Service überstimmt werden. - Audit-Logs MÜSSEN manipulationssicher gespeichert werden.
- Sensitive Daten MÜSSEN vor der Protokollierung redaktiert werden.
requireUserActivationSOLLTE für alle irreversiblen oder extern wirksamen Aktionen gesetzt sein.
Changelog
Abschnitt betitelt „Changelog“| Version | Datum | Änderungen |
|---|---|---|
| 0.1 | 2026-03-27 | Initialer Entwurf |