feat: operator trust root: passkey-signed operator set, signed join codes, nodes verify and pin the chain at enrollment [CI SKIP]
This commit is contained in:
1 parent
321cacac32
commit
fc2bbdcc6d
35 files changed
+1374
-40
No files matched your search
@@ -18,6 +18,11 @@ public static class EndpointConventions
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
/// 这个端点自己要求 passkey 签名(请求里带着断言),比提权窗口更强,所以不再要求窗口:守卫跳过信任类能力的提权检查。
|
||||
/// </summary>
|
||||
public static RouteHandlerBuilder ElevationExempt(this RouteHandlerBuilder builder) => builder.WithMetadata(new ElevationExemptMarker());
|
||||
|
||||
/// <summary>匿名可访问的管理端点(登录):显式声明,对账测试才能区分「忘了声明」。</summary>
|
||||
public static RouteHandlerBuilder AllowsAnonymous(this RouteHandlerBuilder builder) =>
|
||||
builder.WithMetadata(new CapabilityRequirement(null));
|
||||
|
||||
@@ -60,6 +60,9 @@ public static class PrincipalResolver
|
||||
/// </summary>
|
||||
public sealed record CapabilityRequirement(string? Capability);
|
||||
|
||||
/// <summary>端点自己验 passkey 签名(见 <see cref="EndpointConventions.ElevationExempt"/>)。</summary>
|
||||
public sealed record ElevationExemptMarker;
|
||||
|
||||
/// <summary>管理层守卫:按端点声明的能力授权;Cookie 会话的非 GET 请求必须带 <c>X-CSRF-Token</c>。</summary>
|
||||
public static class CapabilityGuard
|
||||
{
|
||||
@@ -90,7 +93,7 @@ public static class CapabilityGuard
|
||||
}
|
||||
|
||||
// 信任类的操作(加节点、吊销、改凭证):登录用户还要有这一种的提权窗口;API key 自己带着能力,不经过这里
|
||||
if (requirement.Capability is { } trusted && Elevation.For(trusted) is { } elevation && ElevationGate.Require(http, elevation, consume: true) is { } needed)
|
||||
if (requirement.Capability is { } trusted && Elevation.For(trusted) is { } elevation && http.GetEndpoint()?.Metadata.GetMetadata<ElevationExemptMarker>() is null && ElevationGate.Require(http, elevation, consume: true) is { } needed)
|
||||
{
|
||||
return needed;
|
||||
}
|
||||
|
||||
@@ -154,7 +154,9 @@ public static class Mappers
|
||||
new(t.Id.Value, t.Scope, t.AgentId?.Value, t.BaseTaskId?.Value, t.Kind, t.Target, t.Params, t.Schedule, t.Enabled, Time(t.UpdatedAtMs));
|
||||
|
||||
public static JoinTokenDto ToDto(JoinTokenInfo t) =>
|
||||
new(t.Id, t.Note, t.Labels, t.AutoApprove, t.MaxUses, t.Uses, Time(t.ExpiresAtMs), Time(t.RevokedAtMs), Time(t.CreatedAtMs), JoinTokenService.RoleOf(t.Kind), t.CreatedBy);
|
||||
new(t.Id, t.Note, t.Labels, t.AutoApprove, t.MaxUses, t.Uses, Time(t.ExpiresAtMs), Time(t.RevokedAtMs), Time(t.CreatedAtMs), JoinTokenService.RoleOf(t.Kind), t.CreatedBy, t.Grant is not null);
|
||||
|
||||
public static TrustStateDto ToDto(TrustState s) => new(s.Initialized, s.Genesis, s.Version, s.InSync, s.Proposal is null ? null : new TrustProposalDto(s.Proposal.Statement, s.Proposal.Version, s.Proposal.Challenge));
|
||||
|
||||
public static ElevationDto ToDto(ElevationWindow w) => new(Elevation.IdOf(w.Class), Time(w.ExpiresAtMs));
|
||||
|
||||
|
||||
Reference in new issue
Block a user