Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion proto/trogonai/agents/agents/v1alpha1/dependencies.proto
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,10 @@ message DelegateDeclaration {
];
// Exactly one known arm is required. Selectors match each Agent's latest
// minted revision's configuration-owned labels. Display names and annotations
// never participate. Session admission pins the selected revision.
// never participate. Session admission pins the selected revision. Resolution
// runs over the Session's hierarchy scope first; the resolved Agent is then
// checked against the dispatching Agent's delegation permissions, which may
// refuse it but never substitute another (ADR#0071).
oneof selection {
option (buf.validate.oneof).required = true;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
edition = "2024";

package trogonai.policy.delegation_permissions.state.v1alpha1;

import "buf/validate/validate.proto";
import "google/protobuf/empty.proto";
import "trogonai/policy/delegation_permissions/v1alpha1/permission_policy.proto";
import "trogonai/policy/subjects/v1alpha1/subject.proto";

// Policy fold only. Replay rejects unknown events, a subject change, repeated
// genesis, and mutations before initialization. Clear retains initialized state.
// Provisioning origin is copied from genesis and never cleared or replaced.
message State {
oneof state {
option (buf.validate.oneof).required = true;

google.protobuf.Empty missing = 1;
InitializedDelegationPermission initialized = 2;
}
}

message InitializedDelegationPermission {
trogonai.policy.subjects.v1alpha1.PolicySubject subject = 1 [features.field_presence = LEGACY_REQUIRED];
// Absence means cleared, which is deny rather than a permit of nothing in
// particular. Restoring targets consults the same history.
trogonai.policy.delegation_permissions.v1alpha1.DelegationPermissionPolicy policy = 2;
string provisioning_id = 3 [(buf.validate.field).cel = {
id: "initialized_delegation_permission.provisioning_id_nonblank"
message: "a supplied provisioning_id must contain a non-whitespace character"
expression: "this.trim() != ''"
}];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
edition = "2024";

package trogonai.policy.delegation_permissions.v1alpha1;

import "trogonai/policy/subjects/v1alpha1/subject.proto";

// Clears only this subject's permit, which returns it to deny unless an
// ancestor node still permits the target. The initialized identity remains.
// Dispatch requires live authority and a nonempty Decider command_id plus the
// original positive expected_revision; retries preserve both. An already cleared
// permission succeeds without an event after that concurrency check. For an
// Agent subject, authoritative registry lifecycle must be ACTIVE or ARCHIVED,
// so requested provisioning setup cannot disappear before activation.
message ClearDelegationPermission {
trogonai.policy.subjects.v1alpha1.PolicySubject subject = 1 [features.field_presence = LEGACY_REQUIRED];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
edition = "2024";

package trogonai.policy.delegation_permissions.v1alpha1;

import "trogonai/policy/subjects/v1alpha1/subject.proto";

// Removes the permission, never the identity. An already cleared history emits
// no second clear.
message DelegationPermissionCleared {
trogonai.policy.subjects.v1alpha1.PolicySubject subject = 1 [features.field_presence = LEGACY_REQUIRED];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
edition = "2024";

package trogonai.policy.delegation_permissions.v1alpha1;

import "buf/validate/validate.proto";
import "trogonai/policy/delegation_permissions/v1alpha1/permission_policy.proto";
import "trogonai/policy/subjects/v1alpha1/subject.proto";

// Genesis fixes the subject for this history. The admitted origin and exact
// initial policy remain immutable receipt evidence after replacements and
// clears, independent of the current policy projection.
message DelegationPermissionInitialized {
trogonai.policy.subjects.v1alpha1.PolicySubject subject = 1 [features.field_presence = LEGACY_REQUIRED];
DelegationPermissionPolicy policy = 2 [features.field_presence = LEGACY_REQUIRED];
string provisioning_id = 3 [(buf.validate.field).cel = {
id: "delegation_permission_initialized.provisioning_id_nonblank"
message: "a supplied provisioning_id must contain a non-whitespace character"
expression: "this.trim() != ''"
}];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
edition = "2024";

package trogonai.policy.delegation_permissions.v1alpha1;

import "trogonai/policy/delegation_permissions/v1alpha1/permission_policy.proto";
import "trogonai/policy/subjects/v1alpha1/subject.proto";

// Replaces the permission in force without replacing the history's identity.
message DelegationPermissionSet {
trogonai.policy.subjects.v1alpha1.PolicySubject subject = 1 [features.field_presence = LEGACY_REQUIRED];
DelegationPermissionPolicy policy = 2 [features.field_presence = LEGACY_REQUIRED];
}
20 changes: 20 additions & 0 deletions proto/trogonai/policy/delegation_permissions/v1alpha1/events.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
edition = "2024";

package trogonai.policy.delegation_permissions.v1alpha1;

import "buf/validate/validate.proto";
import "trogonai/policy/delegation_permissions/v1alpha1/delegation_permission_cleared.proto";
import "trogonai/policy/delegation_permissions/v1alpha1/delegation_permission_initialized.proto";
import "trogonai/policy/delegation_permissions/v1alpha1/delegation_permission_set.proto";

// An unset or unknown event rejects replay; skipping a permission change could
// admit a delegation the current permission forbids, or refuse one it allows.
message DelegationPermissionEvent {
oneof event {
option (buf.validate.oneof).required = true;

DelegationPermissionInitialized delegation_permission_initialized = 1;
DelegationPermissionSet delegation_permission_set = 2;
DelegationPermissionCleared delegation_permission_cleared = 3;
}
}
49 changes: 49 additions & 0 deletions proto/trogonai/policy/delegation_permissions/v1alpha1/faults.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
edition = "2024";

package trogonai.policy.delegation_permissions.v1alpha1;

import "trogon/error/v1alpha1/options.proto";

// Schema-only templates for the policy.delegation_permissions module's
// DeciderService refusals. These messages are never encoded. Administration
// authorization and delegation dispatch admission keep their own failure
// contracts; this fold only owns permission mutations.
message DelegationPermissionCommandInvalidError {
option (trogon.error.v1alpha1.message).template = {
domain: "policy.delegation_permissions"
reason: "DELEGATION_PERMISSION_COMMAND_INVALID"
message: "The command violates the delegation permission policy contract."
code: FAILED_PRECONDITION
visibility: VISIBILITY_PUBLIC
};
}

message DelegationPermissionNotInitializedError {
option (trogon.error.v1alpha1.message).template = {
domain: "policy.delegation_permissions"
reason: "DELEGATION_PERMISSION_NOT_INITIALIZED"
message: "The delegation permission history must be initialized before this command."
code: FAILED_PRECONDITION
visibility: VISIBILITY_PUBLIC
};
}

message DelegationPermissionAlreadyInitializedError {
option (trogon.error.v1alpha1.message).template = {
domain: "policy.delegation_permissions"
reason: "DELEGATION_PERMISSION_ALREADY_INITIALIZED"
message: "The delegation permission history has already been initialized."
code: FAILED_PRECONDITION
visibility: VISIBILITY_PUBLIC
};
}

message DelegationPermissionSubjectMismatchError {
option (trogon.error.v1alpha1.message).template = {
domain: "policy.delegation_permissions"
reason: "DELEGATION_PERMISSION_SUBJECT_MISMATCH"
message: "The command names a different subject from this delegation permission history."
code: FAILED_PRECONDITION
visibility: VISIBILITY_PUBLIC
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
edition = "2024";

package trogonai.policy.delegation_permissions.v1alpha1;

import "buf/validate/validate.proto";
import "trogonai/policy/delegation_permissions/v1alpha1/permission_policy.proto";
import "trogonai/policy/subjects/v1alpha1/subject.proto";

// Exists for the same reason as budget initialization: with absence meaning
// deny, an Agent provisioned with a REQUIRED delegate declaration would fail its
// first Session unless the provisioning operation can install its permission.
// provisioning_id is valid only for an Agent subject. Dispatch verifies the
// subject exists and live administration authority. During PROVISIONING only the
// owning operation may initialize, and dispatch verifies registry origin rather
// than trusting caller-supplied provenance; PROVISIONING_CANCELLED and unknown
// lifecycle reject. NoStream creation requires a nonempty Decider command_id and
// no expected_revision; retries preserve the id. An already-initialized
// rejection is not success; recovery verifies the durable genesis receipt's
// subject, provisioning origin, and exact policy.
message InitializeDelegationPermission {
trogonai.policy.subjects.v1alpha1.PolicySubject subject = 1 [features.field_presence = LEGACY_REQUIRED];
DelegationPermissionPolicy policy = 2 [features.field_presence = LEGACY_REQUIRED];
string provisioning_id = 3 [(buf.validate.field).cel = {
id: "initialize_delegation_permission.provisioning_id_nonblank"
message: "a supplied provisioning_id must contain a non-whitespace character"
expression: "this.trim() != ''"
}];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
edition = "2024";

package trogonai.policy.delegation_permissions.v1alpha1;

import "buf/validate/validate.proto";
import "trogon/hierarchy/v1alpha1/node.proto";
import "trogonai/agents/agents/v1alpha1/identity.proto";

// One thing a dispatching Agent may delegate to: an exact Agent, or every Agent
// placed at or below a node. Both are identities, never selectors, so a relabel
// cannot widen a permission.
message DelegationTarget {
oneof target {
option (buf.validate.oneof).required = true;

trogonai.agents.agents.v1alpha1.AgentId agent_id = 1;
trogon.hierarchy.v1alpha1.NodeId agents_under = 2;
}
}

// A permission widens; it is the grant that lets a Session of the subject
// dispatch a delegation to a target Agent. Absence is deny: an Agent with no
// permission on itself or any ancestor node may not delegate at all, and a
// DelegateDeclaration in its configuration grants nothing (ADR#0025, ADR#0063
// Decision 5).
//
// Permits accumulate downward: the effective set for an Agent is the union of
// its own permission and every ancestor node's. A dispatch is admitted when the
// resolved target Agent is named exactly or is placed at or below a permitted
// node. Permits do not follow the delegation lineage: each dispatch is checked
// against the dispatching Agent's own chain, so a permit to reach one Agent
// never lets that Agent reach a third.
//
// The selector resolves first over the Session's hierarchy scope, ambiguity
// fails there, and the permission check then runs on the single resolved Agent.
// Policy may deny a resolution but never changes which Agent it resolves to.
//
// An empty policy is invalid; clear the permission to withdraw it.
message DelegationPermissionPolicy {
option (buf.validate.message).cel = {
id: "delegation_permission_policy.targets_unique"
message: "each delegation target may appear at most once"
expression: "this.permitted.map(t, has(t.agent_id) ? 'agent:' + t.agent_id.value : 'node:' + t.agents_under.value).unique()"
};

repeated DelegationTarget permitted = 1 [(buf.validate.field).repeated.min_items = 1];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
edition = "2024";

package trogonai.policy.delegation_permissions.v1alpha1;

import "trogonai/policy/delegation_permissions/v1alpha1/permission_policy.proto";
import "trogonai/policy/subjects/v1alpha1/subject.proto";

// Replaces an initialized subject's permission, including after a clear.
// Dispatch requires live administration authority and a nonempty Decider
// command_id plus original positive expected_revision. Retries preserve both; a
// refreshed revision is a new intent. Equal targets succeed without an event
// after the concurrency check; reordering targets alone is not a change. For an
// Agent subject, authoritative registry lifecycle must be ACTIVE or ARCHIVED, so
// requested provisioning setup cannot be replaced before activation. Genesis
// provisioning origin survives every replacement.
message SetDelegationPermission {
trogonai.policy.subjects.v1alpha1.PolicySubject subject = 1 [features.field_presence = LEGACY_REQUIRED];
DelegationPermissionPolicy policy = 2 [features.field_presence = LEGACY_REQUIRED];
}
1 change: 1 addition & 0 deletions proto/trogonai/policy/subjects/v1alpha1/rule_ref.proto
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ enum PolicyRuleKind {
POLICY_RULE_KIND_AGENT_RATE_LIMIT = 2;
POLICY_RULE_KIND_HOLD = 3;
POLICY_RULE_KIND_MODEL_CEILING = 4;
POLICY_RULE_KIND_DELEGATION_PERMISSION = 5;
}

message PolicyRuleRef {
Expand Down
Loading