forked from EduCraft/curriculum-project-hub
docs: define platform admin identity boundary
This commit is contained in:
@@ -0,0 +1,221 @@
|
||||
import Spec.Prelude
|
||||
|
||||
/-!
|
||||
# PlatformAdministration —— 平台管理员身份、会话与审计边界(ADR-0023)
|
||||
|
||||
平台控制面可以创建 org、写入连接凭据并制动全平台工作负载,因此不得借用客户
|
||||
`User`、`OrganizationMembership` 或 project role。ADR-0023 决定独立平台飞书 issuer、
|
||||
单一平级管理员角色、绑定身份的 invitation、可撤销服务端 session、mutation 与平台审计
|
||||
同成同败、最后管理员保护,以及无常驻账号的双因子离线恢复。
|
||||
|
||||
本模块只钉死这些会导致安全边界分歧的语义。cookie 属性、token hash、具体 TTL、审计
|
||||
字段表示/保留期、recovery key 介质和 CLI/SQL 机制仍为 `OPEN`,由对应实现决策承载。
|
||||
-/
|
||||
|
||||
namespace Spec.System
|
||||
|
||||
variable (I : Identifiers)
|
||||
|
||||
/-- 平台管理员的已验证外部身份(`PINNED`, ADR-0023):issuer 必须是专用
|
||||
Platform-owned Feishu Application;该身份与客户 `User`/org membership/project grant
|
||||
是不同的授权根,即使现实中是同一个人也不自动传播权限。 -/
|
||||
structure PlatformIdentity where
|
||||
/-- 平台身份自身标识(`OPEN` 表示,ADR-0023)。 -/
|
||||
id : I.PlatformIdentityId
|
||||
/-- 验证该身份的平台自有飞书应用(`PINNED`, ADR-0023)。 -/
|
||||
application : I.PlatformFeishuApplicationId
|
||||
/-- 在该平台应用作用域内验证的外部飞书用户(`PINNED` 作用域,表示 `OPEN`)。 -/
|
||||
externalUser : I.PlatformExternalUserId
|
||||
|
||||
/-- 平台身份来自当前唯一受信 platform-owned app iff identity 的 issuer 与配置的
|
||||
平台应用相同(`PINNED`, ADR-0023);不能把客户 org app 的 identity 当平台身份。 -/
|
||||
def PlatformIdentity.FromPlatformApplication
|
||||
(identity : PlatformIdentity I)
|
||||
(platformApplication : I.PlatformFeishuApplicationId) : Prop :=
|
||||
identity.application = platformApplication
|
||||
|
||||
/-- 初始平台控制面的 standing role(`PINNED` 封闭, ADR-0023):只有一个平级
|
||||
administrator;不存在 Platform Owner/Super Admin/Teacher 层级。 -/
|
||||
inductive PlatformRole where
|
||||
| administrator
|
||||
|
||||
/-- Standing Platform Administrator grant 的生命周期(`PINNED`, ADR-0023)。 -/
|
||||
inductive StandingPlatformAdminGrantState where
|
||||
| active
|
||||
| revoked
|
||||
|
||||
/-- 一个普通、长期存在的 Platform Administrator grant(`PINNED`, ADR-0023)。 -/
|
||||
structure StandingPlatformAdminGrant where
|
||||
/-- 被授予平台管理员权力的独立平台身份(`PINNED`, ADR-0023)。 -/
|
||||
identity : I.PlatformIdentityId
|
||||
/-- standing role;当前封闭集合只有 administrator(`PINNED`, ADR-0023)。 -/
|
||||
role : PlatformRole
|
||||
/-- grant 当前是否仍有效(`PINNED`, ADR-0023)。 -/
|
||||
state : StandingPlatformAdminGrantState
|
||||
|
||||
/-- Standing grant 仅在 active 状态有效(`PINNED`, ADR-0023)。 -/
|
||||
def StandingPlatformAdminGrant.Active
|
||||
(grant : StandingPlatformAdminGrant I) : Prop :=
|
||||
grant.state = .active
|
||||
|
||||
/-- 首位平台管理员 bootstrap 的前置条件(`PINNED`, ADR-0023):只有 standing admin
|
||||
集合为空时才允许;bootstrap 身份验证、审计与事务机制见 ADR,具体脚本表示 `OPEN`。 -/
|
||||
def CanBootstrapPlatformAdmin
|
||||
(activeStandingAdmins : List I.PlatformIdentityId) : Prop :=
|
||||
activeStandingAdmins = []
|
||||
|
||||
/-- 撤销 standing Platform Administrator 的最后管理员保护(`PINNED`, ADR-0023):
|
||||
target 必须当前有效,且列表中必须另有一个不同的有效管理员。Emergency grant 不计入
|
||||
standing admin 集合,不能用来绕过最后管理员保护。 -/
|
||||
def CanRevokePlatformAdmin
|
||||
(activeStandingAdmins : List I.PlatformIdentityId)
|
||||
(target : I.PlatformIdentityId) : Prop :=
|
||||
target ∈ activeStandingAdmins ∧
|
||||
∃ other, other ∈ activeStandingAdmins ∧ other ≠ target
|
||||
|
||||
/-- Platform Administrator invitation 的生命周期(`PINNED`, ADR-0023):accepted/
|
||||
expired/revoked 都是终态,所以邀请只能成功领取一次。 -/
|
||||
inductive PlatformAdminInvitationState where
|
||||
| pending
|
||||
| accepted
|
||||
| expired
|
||||
| revoked
|
||||
|
||||
/-- 一个短期、单次且绑定具体平台飞书账号的管理员邀请(`PINNED`, ADR-0023)。 -/
|
||||
structure PlatformAdminInvitation where
|
||||
/-- invitation 标识(`OPEN` 表示,ADR-0023)。 -/
|
||||
id : I.PlatformInvitationId
|
||||
/-- 预期账号必须来自这个平台自有飞书应用(`PINNED`, ADR-0023)。 -/
|
||||
application : I.PlatformFeishuApplicationId
|
||||
/-- 只有这个预期飞书账号可领取;链接本身不是 bearer admin 权力(`PINNED`)。 -/
|
||||
expectedExternalUser : I.PlatformExternalUserId
|
||||
/-- 邀请过期的逻辑时刻(`PINNED` 有限寿命,数值单位/上限 `OPEN`)。 -/
|
||||
expiresAt : Nat
|
||||
/-- 邀请当前状态(`PINNED`, ADR-0023)。 -/
|
||||
state : PlatformAdminInvitationState
|
||||
|
||||
/-- 邀请可领取 iff 尚 pending、未过期且已验证 identity 与邀请绑定的 app+用户一致
|
||||
(`PINNED`, ADR-0023)。 -/
|
||||
def PlatformAdminInvitation.CanAccept
|
||||
(invitation : PlatformAdminInvitation I)
|
||||
(identity : PlatformIdentity I)
|
||||
(now : Nat) : Prop :=
|
||||
invitation.state = .pending ∧
|
||||
now < invitation.expiresAt ∧
|
||||
identity.application = invitation.application ∧
|
||||
identity.externalUser = invitation.expectedExternalUser
|
||||
|
||||
/-- 邀请状态转换(`PINNED`, ADR-0023):pending 只能结束为 accepted/expired/revoked;
|
||||
任何终态都不能回到 pending 或再次 accepted。 -/
|
||||
def PlatformAdminInvitation.ValidTransition :
|
||||
PlatformAdminInvitationState → PlatformAdminInvitationState → Prop
|
||||
| .pending, .accepted | .pending, .expired | .pending, .revoked => True
|
||||
| _, _ => False
|
||||
|
||||
/-- 服务端 Platform Session 的生命周期(`PINNED`, ADR-0023)。 -/
|
||||
inductive PlatformSessionState where
|
||||
| active
|
||||
| revoked
|
||||
| expired
|
||||
|
||||
/-- 独立平台会话(`PINNED`, ADR-0023):只绑定 Platform Identity,不携带 org/project
|
||||
权力;opaque cookie/token、hash 与 TTL 表示为 `OPEN`。 -/
|
||||
structure PlatformSession where
|
||||
/-- 平台会话标识(`OPEN` 表示,ADR-0023)。 -/
|
||||
id : I.PlatformSessionId
|
||||
/-- 会话认证的独立平台身份(`PINNED`, ADR-0023)。 -/
|
||||
identity : I.PlatformIdentityId
|
||||
/-- 服务端可立即撤销/过期的状态(`PINNED`, ADR-0023)。 -/
|
||||
state : PlatformSessionState
|
||||
|
||||
/-- 双因子离线恢复授权(`PINNED`, ADR-0023):受控主机权限、主机外 recovery key 与
|
||||
已声明 incident 三项都存在才是受支持的 recovery;具体因子实现与保管介质 `OPEN`。 -/
|
||||
structure PlatformRecoveryAuthorization where
|
||||
/-- 已验证受控生产主机权限(`PINNED`, ADR-0023)。 -/
|
||||
hostControl : Bool
|
||||
/-- 已验证独立的主机外 recovery key(`PINNED`, ADR-0023)。 -/
|
||||
offlineRecoveryKey : Bool
|
||||
/-- 操作绑定了 incident id 与原因(`PINNED`, ADR-0023)。 -/
|
||||
incidentDeclared : Bool
|
||||
|
||||
/-- Recovery authorization 只有三项因子均为真时有效(`PINNED`, ADR-0023)。 -/
|
||||
def PlatformRecoveryAuthorization.Valid
|
||||
(authorization : PlatformRecoveryAuthorization) : Prop :=
|
||||
authorization.hostControl = true ∧
|
||||
authorization.offlineRecoveryKey = true ∧
|
||||
authorization.incidentDeclared = true
|
||||
|
||||
/-- 只有有效双因子 recovery authorization 才能签发 Emergency Platform Grant
|
||||
(`PINNED`, ADR-0023);不存在普通 web session 直接创建 break-glass 权力的路径。 -/
|
||||
def CanIssueEmergencyPlatformGrant
|
||||
(authorization : PlatformRecoveryAuthorization) : Prop :=
|
||||
authorization.Valid
|
||||
|
||||
/-- 无常驻 break-glass 账号的短期紧急授权(`PINNED`, ADR-0023)。它不属于 standing
|
||||
role,必须绑定已声明 incident,自动过期且可在恢复完成时提前关闭。 -/
|
||||
structure EmergencyPlatformGrant where
|
||||
/-- 获得临时平台权力的已验证 Platform Identity(`PINNED`, ADR-0023)。 -/
|
||||
identity : I.PlatformIdentityId
|
||||
/-- 触发该授权的 incident(`PINNED`, ADR-0023)。 -/
|
||||
incident : I.PlatformIncidentId
|
||||
/-- 自动过期的逻辑时刻(`PINNED` 有限寿命,数值单位/上限 `OPEN`)。 -/
|
||||
expiresAt : Nat
|
||||
/-- 恢复完成后是否已显式关闭(`PINNED`, ADR-0023)。 -/
|
||||
closed : Bool
|
||||
|
||||
/-- Emergency grant 仅在未关闭且未到期时有效(`PINNED`, ADR-0023)。 -/
|
||||
def EmergencyPlatformGrant.Active
|
||||
(grant : EmergencyPlatformGrant I) (now : Nat) : Prop :=
|
||||
grant.closed = false ∧ now < grant.expiresAt
|
||||
|
||||
/-- 每次平台请求的授权条件(`PINNED`, ADR-0023):session 必须仍为 active,且请求时
|
||||
重新解析到 active standing grant 或同 identity 的未关闭、未过期 emergency grant。
|
||||
cookie 内曾经出现过 role claim 不能代替这次解析。 -/
|
||||
def PlatformSession.Authorized
|
||||
(session : PlatformSession I)
|
||||
(standingGrants : List (StandingPlatformAdminGrant I))
|
||||
(emergencyGrants : List (EmergencyPlatformGrant I))
|
||||
(now : Nat) : Prop :=
|
||||
session.state = .active ∧
|
||||
((∃ grant, grant ∈ standingGrants ∧
|
||||
grant.identity = session.identity ∧
|
||||
StandingPlatformAdminGrant.Active I grant) ∨
|
||||
∃ grant, grant ∈ emergencyGrants ∧
|
||||
grant.identity = session.identity ∧
|
||||
EmergencyPlatformGrant.Active I grant now)
|
||||
|
||||
/-- 必须做近期 OAuth step-up 的平台敏感操作集合(`PINNED`, ADR-0023;未来新增敏感
|
||||
操作时可扩):管理员生命周期、飞书连接、platform-managed provider 凭据、org 生命周期、
|
||||
workload brake 与 emergency grant 都不能只凭旧 session。 -/
|
||||
inductive PlatformSensitiveAction where
|
||||
| administratorLifecycle
|
||||
| feishuConnection
|
||||
| platformManagedProviderCredential
|
||||
| organizationLifecycle
|
||||
| workloadBrake
|
||||
| emergencyGrant
|
||||
|
||||
/-- 敏感操作授权必须提供"近期重新认证"事实(`PINNED`, ADR-0023);具体时间窗 `OPEN`,
|
||||
由 browser/session 决策给出受检上限。 -/
|
||||
def PlatformSensitiveAction.Authorized
|
||||
(_action : PlatformSensitiveAction)
|
||||
(recentAuthentication : Prop) : Prop :=
|
||||
recentAuthentication
|
||||
|
||||
/-- 一个成功平台 mutation 与其独立 Platform Audit Entry 的原子提交事实(`PINNED`,
|
||||
ADR-0023):没有 audit entry 就不存在合法成功 commit;具体数据库事务机制 `OPEN`。 -/
|
||||
structure PlatformMutationCommit where
|
||||
/-- 成功的平台 mutation(`PINNED`, ADR-0023)。 -/
|
||||
mutation : I.PlatformMutationId
|
||||
/-- 与 mutation 同成同败的 append-only 平台审计条目(`PINNED`, ADR-0023)。 -/
|
||||
auditEntry : I.PlatformAuditEntryId
|
||||
|
||||
/-- Organization 管理员可读的平台审计脱敏投影(`PINNED`, ADR-0023):只关联影响该
|
||||
Organization 的 entry;完整平台审计和其他 org entry 不经此投影暴露。 -/
|
||||
structure OrganizationPlatformAuditProjection where
|
||||
/-- 被投影的平台审计条目(`PINNED`, ADR-0023)。 -/
|
||||
auditEntry : I.PlatformAuditEntryId
|
||||
/-- 唯一可见该投影的受影响 Organization(`PINNED`, ADR-0023)。 -/
|
||||
organization : I.OrganizationId
|
||||
|
||||
end Spec.System
|
||||
Reference in New Issue
Block a user