Certificate Signing Request submitted by an agent. Step 1 of the PKI lifecycle: Agent generates a keypair locally, then submits this CSR with the public key and metadata. The Org CA validates the request and issues a signed certificate.
| 205 | |
| 206 | |
| 207 | class AgentIdentityCSR(BaseModel): |
| 208 | """ |
| 209 | Certificate Signing Request submitted by an agent. |
| 210 | |
| 211 | Step 1 of the PKI lifecycle: Agent generates a keypair locally, |
| 212 | then submits this CSR with the public key and metadata. |
| 213 | The Org CA validates the request and issues a signed certificate. |
| 214 | """ |
| 215 | csr_id: str = Field( |
| 216 | default_factory=lambda: "csr_" + uuid4().hex[:12], |
| 217 | description="Unique CSR identifier.", |
| 218 | ) |
| 219 | agent_name: str = Field( |
| 220 | min_length=2, max_length=64, |
| 221 | description="Human-readable agent name, unique per org.", |
| 222 | ) |
| 223 | org_id: str = Field( |
| 224 | min_length=2, max_length=64, |
| 225 | description="Target organization identifier.", |
| 226 | ) |
| 227 | requested_ou: str = Field( |
| 228 | min_length=1, max_length=64, |
| 229 | description="Requested Organizational Unit that will authorize issuance.", |
| 230 | ) |
| 231 | public_key: str = Field( |
| 232 | description="Ed25519 public key in Base64url encoding.", |
| 233 | ) |
| 234 | purpose: str = Field( |
| 235 | min_length=1, max_length=256, |
| 236 | description="Intended purpose of this agent identity.", |
| 237 | ) |
| 238 | metadata: dict[str, str] = Field( |
| 239 | default_factory=dict, |
| 240 | description="Additional metadata (e.g., environment, version).", |
| 241 | ) |
| 242 | requested_validity_days: int | None = Field( |
| 243 | default=None, ge=1, le=3650, |
| 244 | description="Requested validity period in days (null = no expiry).", |
| 245 | ) |
| 246 | submitted_at: datetime = Field(default_factory=_now_utc) |
| 247 | |
| 248 | @field_validator("public_key") |
| 249 | @classmethod |
| 250 | def _validate_public_key(cls, v: str) -> str: |
| 251 | if not _B64URL_RE.match(v): |
| 252 | raise ValueError( |
| 253 | "public_key must be a 43-44 char Base64url Ed25519 public key." |
| 254 | ) |
| 255 | return v |
| 256 | |
| 257 | @field_validator("agent_name") |
| 258 | @classmethod |
| 259 | def _validate_agent_name(cls, v: str) -> str: |
| 260 | if not _AGENT_NAME_RE.match(v): |
| 261 | raise ValueError(f"agent_name '{v}' must match ^[a-z][a-z0-9_-]*$") |
| 262 | return v |
| 263 | |
| 264 | @field_validator("org_id") |