mirror of
https://github.com/coder/coder.git
synced 2026-11-03 05:55:24 +08:00
Add the `chat_model_config` RBAC resource, actions, and API key scopes. This layer includes the scope migration and generated API types. Model list queries apply token scopes, SQL authorization filters, and row ACLs. Write and default-management handlers keep deployment configuration authorization until the next API layer replaces it. Depends on #27956 _This pull request description was generated by Coder Agents._
204 lines
7.2 KiB
Go
204 lines
7.2 KiB
Go
package regosql
|
|
|
|
import "github.com/coder/coder/v2/coderd/rbac/regosql/sqltypes"
|
|
|
|
func resourceIDMatcher() sqltypes.VariableMatcher {
|
|
return sqltypes.StringVarMatcher("id :: text", []string{"input", "object", "id"})
|
|
}
|
|
|
|
func chatResourceIDMatcher() sqltypes.VariableMatcher {
|
|
return sqltypes.StringVarMatcher("chats_expanded.id :: text", []string{"input", "object", "id"})
|
|
}
|
|
|
|
func organizationOwnerMatcher() sqltypes.VariableMatcher {
|
|
return sqltypes.StringVarMatcher("organization_id :: text", []string{"input", "object", "org_owner"})
|
|
}
|
|
|
|
func userOwnerMatcher() sqltypes.VariableMatcher {
|
|
return sqltypes.StringVarMatcher("owner_id :: text", []string{"input", "object", "owner"})
|
|
}
|
|
|
|
func groupACLMatcher(m sqltypes.VariableMatcher) ACLMappingVar {
|
|
return ACLMappingMatcher(m, "group_acl", []string{"input", "object", "acl_group_list"})
|
|
}
|
|
|
|
func userACLMatcher(m sqltypes.VariableMatcher) ACLMappingVar {
|
|
return ACLMappingMatcher(m, "user_acl", []string{"input", "object", "acl_user_list"})
|
|
}
|
|
|
|
func TemplateConverter() *sqltypes.VariableConverter {
|
|
matcher := sqltypes.NewVariableConverter().RegisterMatcher(
|
|
resourceIDMatcher(),
|
|
sqltypes.StringVarMatcher("t.organization_id :: text", []string{"input", "object", "org_owner"}),
|
|
// Templates have no user owner, only owner by an organization.
|
|
sqltypes.AlwaysFalse(userOwnerMatcher()),
|
|
)
|
|
matcher.RegisterMatcher(
|
|
groupACLMatcher(matcher),
|
|
userACLMatcher(matcher),
|
|
)
|
|
return matcher
|
|
}
|
|
|
|
func WorkspaceConverter() *sqltypes.VariableConverter {
|
|
matcher := sqltypes.NewVariableConverter().RegisterMatcher(
|
|
resourceIDMatcher(),
|
|
sqltypes.StringVarMatcher("workspaces.organization_id :: text", []string{"input", "object", "org_owner"}),
|
|
userOwnerMatcher(),
|
|
)
|
|
matcher.RegisterMatcher(
|
|
ACLMappingMatcher(matcher, "workspaces.group_acl", []string{"input", "object", "acl_group_list"}).UsingSubfield("permissions"),
|
|
ACLMappingMatcher(matcher, "workspaces.user_acl", []string{"input", "object", "acl_user_list"}).UsingSubfield("permissions"),
|
|
)
|
|
|
|
return matcher
|
|
}
|
|
|
|
func ChatConverter() *sqltypes.VariableConverter {
|
|
matcher := chatBaseConverter()
|
|
matcher.RegisterMatcher(
|
|
ACLMappingMatcher(matcher, "chats_expanded.group_acl", []string{"input", "object", "acl_group_list"}).UsingSubfield("permissions"),
|
|
ACLMappingMatcher(matcher, "chats_expanded.user_acl", []string{"input", "object", "acl_user_list"}).UsingSubfield("permissions"),
|
|
)
|
|
|
|
return matcher
|
|
}
|
|
|
|
func ChatNoACLConverter() *sqltypes.VariableConverter {
|
|
matcher := chatBaseConverter()
|
|
matcher.RegisterMatcher(
|
|
sqltypes.AlwaysFalse(groupACLMatcher(matcher)),
|
|
sqltypes.AlwaysFalse(userACLMatcher(matcher)),
|
|
)
|
|
|
|
return matcher
|
|
}
|
|
|
|
func MCPServerConfigConverter() *sqltypes.VariableConverter {
|
|
matcher := sqltypes.NewVariableConverter().RegisterMatcher(
|
|
resourceIDMatcher(),
|
|
sqltypes.StringVarMatcher("mcp_server_configs.organization_id :: text", []string{"input", "object", "org_owner"}),
|
|
sqltypes.AlwaysFalse(userOwnerMatcher()),
|
|
)
|
|
matcher.RegisterMatcher(
|
|
ACLMappingMatcher(matcher, "mcp_server_configs.group_acl", []string{"input", "object", "acl_group_list"}).UsingSubfield("permissions"),
|
|
ACLMappingMatcher(matcher, "mcp_server_configs.user_acl", []string{"input", "object", "acl_user_list"}).UsingSubfield("permissions"),
|
|
)
|
|
return matcher
|
|
}
|
|
|
|
func chatBaseConverter() *sqltypes.VariableConverter {
|
|
return sqltypes.NewVariableConverter().RegisterMatcher(
|
|
chatResourceIDMatcher(),
|
|
sqltypes.StringVarMatcher("chats_expanded.organization_id :: text", []string{"input", "object", "org_owner"}),
|
|
userOwnerMatcher(),
|
|
)
|
|
}
|
|
|
|
// ChatModelConfigConverter qualifies columns against the cmc alias used by
|
|
// GetChatModelConfigs. Chat model configs have no user owner,
|
|
// only an organization owner.
|
|
func ChatModelConfigConverter() *sqltypes.VariableConverter {
|
|
matcher := sqltypes.NewVariableConverter().RegisterMatcher(
|
|
sqltypes.StringVarMatcher("cmc.id :: text", []string{"input", "object", "id"}),
|
|
sqltypes.StringVarMatcher("cmc.organization_id :: text", []string{"input", "object", "org_owner"}),
|
|
sqltypes.AlwaysFalse(userOwnerMatcher()),
|
|
)
|
|
matcher.RegisterMatcher(
|
|
ACLMappingMatcher(matcher, "cmc.group_acl", []string{"input", "object", "acl_group_list"}).UsingSubfield("permissions"),
|
|
ACLMappingMatcher(matcher, "cmc.user_acl", []string{"input", "object", "acl_user_list"}).UsingSubfield("permissions"),
|
|
)
|
|
|
|
return matcher
|
|
}
|
|
|
|
func AuditLogConverter() *sqltypes.VariableConverter {
|
|
matcher := sqltypes.NewVariableConverter().RegisterMatcher(
|
|
resourceIDMatcher(),
|
|
sqltypes.UUIDVarMatcher("audit_logs.organization_id", []string{"input", "object", "org_owner"}),
|
|
// Audit logs have no user owner, only owner by an organization.
|
|
sqltypes.AlwaysFalse(userOwnerMatcher()),
|
|
)
|
|
matcher.RegisterMatcher(
|
|
sqltypes.AlwaysFalse(groupACLMatcher(matcher)),
|
|
sqltypes.AlwaysFalse(userACLMatcher(matcher)),
|
|
)
|
|
return matcher
|
|
}
|
|
|
|
func ConnectionLogConverter() *sqltypes.VariableConverter {
|
|
matcher := sqltypes.NewVariableConverter().RegisterMatcher(
|
|
resourceIDMatcher(),
|
|
sqltypes.UUIDVarMatcher("connection_logs.organization_id", []string{"input", "object", "org_owner"}),
|
|
// Connection logs have no user owner, only owner by an organization.
|
|
sqltypes.AlwaysFalse(userOwnerMatcher()),
|
|
)
|
|
matcher.RegisterMatcher(
|
|
sqltypes.AlwaysFalse(groupACLMatcher(matcher)),
|
|
sqltypes.AlwaysFalse(userACLMatcher(matcher)),
|
|
)
|
|
return matcher
|
|
}
|
|
|
|
func AIBridgeInterceptionConverter() *sqltypes.VariableConverter {
|
|
matcher := sqltypes.NewVariableConverter().RegisterMatcher(
|
|
resourceIDMatcher(),
|
|
// AI Bridge interceptions are not tied to any organization.
|
|
sqltypes.StringVarMatcher("''", []string{"input", "object", "org_owner"}),
|
|
sqltypes.StringVarMatcher("initiator_id :: text", []string{"input", "object", "owner"}),
|
|
)
|
|
matcher.RegisterMatcher(
|
|
// No ACLs on the aibridge interception type
|
|
sqltypes.AlwaysFalse(groupACLMatcher(matcher)),
|
|
sqltypes.AlwaysFalse(userACLMatcher(matcher)),
|
|
)
|
|
return matcher
|
|
}
|
|
|
|
func UserConverter() *sqltypes.VariableConverter {
|
|
matcher := sqltypes.NewVariableConverter().RegisterMatcher(
|
|
resourceIDMatcher(),
|
|
// Users are never owned by an organization, so always return the empty string
|
|
// for the org owner.
|
|
sqltypes.StringVarMatcher("''", []string{"input", "object", "org_owner"}),
|
|
// Users are always owned by themselves.
|
|
sqltypes.StringVarMatcher("id :: text", []string{"input", "object", "owner"}),
|
|
)
|
|
matcher.RegisterMatcher(
|
|
// No ACLs on the user type
|
|
sqltypes.AlwaysFalse(groupACLMatcher(matcher)),
|
|
sqltypes.AlwaysFalse(userACLMatcher(matcher)),
|
|
)
|
|
return matcher
|
|
}
|
|
|
|
// NoACLConverter should be used when the target SQL table does not contain
|
|
// group or user ACL columns.
|
|
func NoACLConverter() *sqltypes.VariableConverter {
|
|
matcher := sqltypes.NewVariableConverter().RegisterMatcher(
|
|
resourceIDMatcher(),
|
|
organizationOwnerMatcher(),
|
|
userOwnerMatcher(),
|
|
)
|
|
matcher.RegisterMatcher(
|
|
sqltypes.AlwaysFalse(groupACLMatcher(matcher)),
|
|
sqltypes.AlwaysFalse(userACLMatcher(matcher)),
|
|
)
|
|
|
|
return matcher
|
|
}
|
|
|
|
func DefaultVariableConverter() *sqltypes.VariableConverter {
|
|
matcher := sqltypes.NewVariableConverter().RegisterMatcher(
|
|
resourceIDMatcher(),
|
|
organizationOwnerMatcher(),
|
|
userOwnerMatcher(),
|
|
)
|
|
matcher.RegisterMatcher(
|
|
groupACLMatcher(matcher),
|
|
userACLMatcher(matcher),
|
|
)
|
|
|
|
return matcher
|
|
}
|