feat(ssh): add multi-organization support for certificate signing

Add support for users who belong to multiple organizations to select
which organization's CA should sign their SSH certificates.

Changes:
- CLI: Add --org-id and --list-orgs options for organization selection
- API: Return MULTIPLE_ORGS_AMBIGUOUS error when org selection needed
- API: Add /users/me/organizations/simple endpoint for CLI org listing
- DB: Add organization_id to certificate_audit_logs for better tracking
- Include organization_name in certificate response for clarity
This commit is contained in:
2026-04-24 22:27:24 +09:30
parent 015c622016
commit cec04f3cb2
8 changed files with 314 additions and 46 deletions
@@ -29,6 +29,14 @@ class CertificateAuditLog(BaseModel):
index=True,
)
# The organization that owns the CA (null for system CAs)
organization_id = db.Column(
db.String(36),
db.ForeignKey("organizations.id"),
nullable=True,
index=True,
)
# Action type (e.g., "signed", "revoked", "validated", "requested")
action = db.Column(db.String(50), nullable=False, index=True)
@@ -50,6 +58,7 @@ class CertificateAuditLog(BaseModel):
# Relationships
certificate = db.relationship("SSHCertificate", back_populates="audit_logs")
user = db.relationship("User")
organization = db.relationship("Organization")
__table_args__ = (
db.Index("idx_cert_audit_cert_action", "certificate_id", "action"),
@@ -68,6 +77,7 @@ class CertificateAuditLog(BaseModel):
certificate_id: str,
action: str,
user_id: str = None,
organization_id: str = None,
**kwargs,
) -> "CertificateAuditLog":
"""Create a certificate audit log entry.
@@ -76,6 +86,7 @@ class CertificateAuditLog(BaseModel):
certificate_id: ID of the certificate
action: Action type (e.g., "signed", "revoked")
user_id: ID of the user performing the action (optional)
organization_id: ID of the organization that owns the CA (optional)
**kwargs: Additional fields (ip_address, user_agent, message, etc.)
Returns:
@@ -85,6 +96,7 @@ class CertificateAuditLog(BaseModel):
certificate_id=certificate_id,
action=action,
user_id=user_id,
organization_id=organization_id,
**kwargs,
)
log_entry.save()