accesscontrol

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 23, 2026 License: GPL-3.0 Imports: 22 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var MembershipCacheServiceErrorIsTransient = func(err error) bool {
	if err == nil {
		return true
	}
	return !errors.Is(err, shared.ErrNotFound)
}

MembershipCacheServiceErrorIsTransient is exposed for tests that want to assert the cache layer never returns a fatal error.

Functions

func ComputeContentHash

func ComputeContentHash(content []byte) string

ComputeContentHash computes a SHA256 hash of the given content.

func GenerateBundleVersion

func GenerateBundleVersion(timestamp time.Time, contentHash string) string

GenerateBundleVersion generates a version string for a bundle.

Types

type AddGroupMemberInput

type AddGroupMemberInput struct {
	GroupID string    `json:"-"`
	UserID  shared.ID `json:"user_id" validate:"required"`
	Role    string    `json:"role" validate:"required,oneof=owner lead member"`
}

AddGroupMemberInput represents the input for adding a member to a group.

type AddPermissionToSetInput

type AddPermissionToSetInput struct {
	PermissionSetID  string `json:"-"`
	PermissionID     string `json:"permission_id" validate:"required"`
	ModificationType string `json:"modification_type" validate:"omitempty,oneof=add remove"`
}

AddPermissionToSetInput represents the input for adding a permission to a set.

type AssignAssetInput

type AssignAssetInput struct {
	GroupID       string `json:"-"`
	AssetID       string `json:"asset_id" validate:"required,uuid"`
	OwnershipType string `json:"ownership_type" validate:"required,oneof=primary secondary stakeholder informed"`
}

AssignAssetInput represents the input for assigning an asset to a group.

type AssignPermissionSetInput

type AssignPermissionSetInput struct {
	GroupID         string `json:"-"`
	PermissionSetID string `json:"permission_set_id" validate:"required"`
}

AssignPermissionSetInput represents the input for assigning a permission set to a group.

type AssignRoleInput

type AssignRoleInput struct {
	TenantID string `json:"-"`
	UserID   string `json:"user_id" validate:"required,uuid"`
	RoleID   string `json:"role_id" validate:"required,uuid"`
}

AssignRoleInput represents the input for assigning a role to a user.

type BulkAssignAssetsInput

type BulkAssignAssetsInput struct {
	GroupID       string   `json:"-"`
	AssetIDs      []string `json:"asset_ids" validate:"required,min=1,max=1000,dive,uuid"`
	OwnershipType string   `json:"ownership_type" validate:"required,oneof=primary secondary stakeholder informed"`
}

BulkAssignAssetsInput represents the input for bulk assigning assets to a group.

type BulkAssignAssetsResult

type BulkAssignAssetsResult struct {
	SuccessCount int      `json:"success_count"`
	FailedCount  int      `json:"failed_count"`
	FailedAssets []string `json:"failed_assets,omitempty"`
}

BulkAssignAssetsResult represents the result of bulk asset assignment.

type BulkAssignRoleToUsersInput

type BulkAssignRoleToUsersInput struct {
	TenantID string   `json:"-"`
	RoleID   string   `json:"role_id" validate:"required,uuid"`
	UserIDs  []string `json:"user_ids" validate:"required,min=1,dive,uuid"`
}

BulkAssignRoleToUsersInput represents the input for bulk role assignment.

type BulkAssignRoleToUsersResult

type BulkAssignRoleToUsersResult struct {
	SuccessCount int      `json:"success_count"`
	FailedCount  int      `json:"failed_count"`
	FailedUsers  []string `json:"failed_users,omitempty"`
}

BulkAssignRoleToUsersResult represents the result of bulk role assignment.

type CachedMembership

type CachedMembership struct {
	ID       string    `json:"id"`
	Role     string    `json:"role"`
	Status   string    `json:"status"`
	JoinedAt time.Time `json:"joined_at"`
}

CachedMembership is the slim DTO stored in Redis. It carries exactly the fields the middleware needs to enforce access control and populate the request context.

type CompleteBundleInput

type CompleteBundleInput struct {
	BundleID     string            `json:"bundle_id" validate:"required,uuid"`
	Version      string            `json:"version" validate:"required,max=50"`
	ContentHash  string            `json:"content_hash" validate:"required,max=64"`
	RuleCount    int               `json:"rule_count" validate:"min=0"`
	SourceCount  int               `json:"source_count" validate:"min=0"`
	SizeBytes    int64             `json:"size_bytes" validate:"min=0"`
	SourceHashes map[string]string `json:"source_hashes"`
	ExpiresAt    *string           `json:"expires_at"` // RFC3339 format
}

CompleteBundleInput represents the input for completing a bundle build.

type CreateBundleInput

type CreateBundleInput struct {
	TenantID    string   `json:"tenant_id" validate:"required,uuid"`
	ToolID      string   `json:"tool_id" validate:"required,uuid"`
	SourceIDs   []string `json:"source_ids" validate:"required,min=1,dive,uuid"`
	StoragePath string   `json:"storage_path" validate:"required,max=500"`
}

CreateBundleInput represents the input for creating a rule bundle.

type CreateGroupInput

type CreateGroupInput struct {
	TenantID           string                       `json:"-"`
	Name               string                       `json:"name" validate:"required,min=2,max=100"`
	Slug               string                       `json:"slug" validate:"required,min=2,max=100,slug"`
	Description        string                       `json:"description" validate:"max=500"`
	GroupType          string                       `json:"group_type" validate:"required,oneof=security_team team department project external"`
	Settings           *groupdom.GroupSettings      `json:"settings,omitempty"`
	NotificationConfig *groupdom.NotificationConfig `json:"notification_config,omitempty"`
}

CreateGroupInput represents the input for creating a group.

type CreateGroupPermissionInput

type CreateGroupPermissionInput struct {
	GroupID      string `json:"-"`
	PermissionID string `json:"permission_id" validate:"required"`
	Effect       string `json:"effect" validate:"required,oneof=allow deny"`
}

CreateGroupPermissionInput represents the input for creating a custom group permission.

type CreateOverrideInput

type CreateOverrideInput struct {
	TenantID         string  `json:"tenant_id" validate:"required,uuid"`
	ToolID           string  `json:"tool_id" validate:"omitempty,uuid"`
	RulePattern      string  `json:"rule_pattern" validate:"required,min=1,max=500"`
	IsPattern        bool    `json:"is_pattern"`
	Enabled          bool    `json:"enabled"`
	SeverityOverride string  `json:"severity_override" validate:"omitempty,oneof=critical high medium low info"`
	AssetGroupID     string  `json:"asset_group_id" validate:"omitempty,uuid"`
	ScanProfileID    string  `json:"scan_profile_id" validate:"omitempty,uuid"`
	Reason           string  `json:"reason" validate:"max=1000"`
	CreatedBy        string  `json:"created_by" validate:"omitempty,uuid"`
	ExpiresAt        *string `json:"expires_at"` // RFC3339 format
}

CreateOverrideInput represents the input for creating a rule override.

type CreatePermissionSetInput

type CreatePermissionSetInput struct {
	TenantID    string   `json:"-"`
	Name        string   `json:"name" validate:"required,min=2,max=100"`
	Slug        string   `json:"slug" validate:"required,min=2,max=100,slug"`
	Description string   `json:"description" validate:"max=500"`
	SetType     string   `json:"set_type" validate:"required,oneof=custom extended cloned"`
	ParentSetID *string  `json:"parent_set_id,omitempty"`
	Permissions []string `json:"permissions,omitempty"` // List of permission IDs to add
}

CreatePermissionSetInput represents the input for creating a permission set.

type CreateRoleInput

type CreateRoleInput struct {
	TenantID          string   `json:"-"`
	Slug              string   `json:"slug" validate:"required,min=2,max=50,slug"`
	Name              string   `json:"name" validate:"required,min=2,max=100"`
	Description       string   `json:"description" validate:"max=500"`
	HierarchyLevel    int      `json:"hierarchy_level" validate:"min=0,max=100"`
	HasFullDataAccess bool     `json:"has_full_data_access"`
	Permissions       []string `json:"permissions"`
}

CreateRoleInput represents the input for creating a role.

type CreateSourceInput

type CreateSourceInput struct {
	TenantID            string `json:"tenant_id" validate:"required,uuid"`
	ToolID              string `json:"tool_id" validate:"omitempty,uuid"`
	Name                string `json:"name" validate:"required,min=1,max=255"`
	Description         string `json:"description" validate:"max=1000"`
	SourceType          string `json:"source_type" validate:"required,oneof=git http local"`
	Config              []byte `json:"config" validate:"required"`
	CredentialsID       string `json:"credentials_id" validate:"omitempty,uuid"`
	SyncEnabled         bool   `json:"sync_enabled"`
	SyncIntervalMinutes int    `json:"sync_interval_minutes" validate:"min=5,max=10080"`
	Priority            int    `json:"priority" validate:"min=0,max=1000"`
}

CreateSourceInput represents the input for creating a rule source.

type GroupCounts

type GroupCounts struct {
	MemberCount int
	AssetCount  int
}

GroupCounts holds member and asset counts for a group.

type GroupService

type GroupService struct {
	// contains filtered or unexported fields
}

GroupService handles group-related business operations.

func NewGroupService

func NewGroupService(
	repo groupdom.Repository,
	log *logger.Logger,
	opts ...GroupServiceOption,
) *GroupService

NewGroupService creates a new GroupService.

func (*GroupService) AddMember

AddMember adds a user to a group.

func (*GroupService) AssignAsset

func (s *GroupService) AssignAsset(ctx context.Context, input AssignAssetInput, assignedBy shared.ID, actx auditapp.AuditContext) error

AssignAsset assigns an asset to a group with the specified ownership type.

func (*GroupService) AssignPermissionSet

func (s *GroupService) AssignPermissionSet(ctx context.Context, input AssignPermissionSetInput, assignedBy shared.ID, actx auditapp.AuditContext) error

AssignPermissionSet assigns a permission set to a group.

func (*GroupService) BulkAssignAssets

func (s *GroupService) BulkAssignAssets(ctx context.Context, input BulkAssignAssetsInput, assignedBy shared.ID, actx auditapp.AuditContext) (*BulkAssignAssetsResult, error)

BulkAssignAssets assigns multiple assets to a group in bulk.

func (*GroupService) CanAccessAsset

func (s *GroupService) CanAccessAsset(ctx context.Context, userID shared.ID, assetID string) (bool, error)

CanAccessAsset checks if a user can access an asset through their group memberships.

func (*GroupService) CountUniqueMembers

func (s *GroupService) CountUniqueMembers(ctx context.Context, groups []*groupdom.Group) (int, error)

CountUniqueMembers counts the number of distinct users across the given groups.

func (*GroupService) CreateGroup

func (s *GroupService) CreateGroup(ctx context.Context, input CreateGroupInput, creatorUserID shared.ID, actx auditapp.AuditContext) (*groupdom.Group, error)

CreateGroup creates a new group.

func (*GroupService) DeleteGroup

func (s *GroupService) DeleteGroup(ctx context.Context, groupID string, actx auditapp.AuditContext) error

DeleteGroup deletes a group.

func (*GroupService) GetGroup

func (s *GroupService) GetGroup(ctx context.Context, groupID string) (*groupdom.Group, error)

GetGroup retrieves a group by ID.

func (*GroupService) GetGroupBySlug

func (s *GroupService) GetGroupBySlug(ctx context.Context, tenantID, slug string) (*groupdom.Group, error)

GetGroupBySlug retrieves a group by tenant and slug.

func (*GroupService) GetGroupCounts

func (s *GroupService) GetGroupCounts(ctx context.Context, groups []*groupdom.Group) (map[shared.ID]GroupCounts, error)

GetGroupCounts returns member and asset counts for the given groups.

func (*GroupService) GetGroupSecure

func (s *GroupService) GetGroupSecure(ctx context.Context, tenantID, groupID string) (*groupdom.Group, error)

GetGroupSecure retrieves a group by tenant and ID (tenant-scoped access control).

func (*GroupService) ListAssetOwners

func (s *GroupService) ListAssetOwners(ctx context.Context, assetID string) ([]*accesscontroldom.AssetOwner, error)

ListAssetOwners lists all groups that own an asset.

func (*GroupService) ListGroupAssets

func (s *GroupService) ListGroupAssets(ctx context.Context, groupID string, limit, offset int) ([]*accesscontroldom.AssetOwnerWithAsset, int64, error)

ListGroupAssets lists assets assigned to a group with asset details, with pagination.

func (*GroupService) ListGroupMembers

func (s *GroupService) ListGroupMembers(ctx context.Context, groupID string) ([]*groupdom.Member, error)

ListGroupMembers lists all members of a group.

func (*GroupService) ListGroupMembersWithUserInfo

func (s *GroupService) ListGroupMembersWithUserInfo(ctx context.Context, groupID string, limit, offset int) ([]*groupdom.MemberWithUser, int64, error)

ListGroupMembersWithUserInfo lists members with user details, with pagination.

func (*GroupService) ListGroupPermissionSets

func (s *GroupService) ListGroupPermissionSets(ctx context.Context, groupID string) ([]shared.ID, error)

ListGroupPermissionSets lists permission sets assigned to a group.

func (*GroupService) ListGroupPermissionSetsWithDetails

func (s *GroupService) ListGroupPermissionSetsWithDetails(ctx context.Context, groupID string) ([]*permissionsetdom.PermissionSetWithItems, error)

ListGroupPermissionSetsWithDetails lists permission sets assigned to a group with full details.

func (*GroupService) ListGroups

func (s *GroupService) ListGroups(ctx context.Context, input ListGroupsInput) (*ListGroupsOutput, error)

ListGroups lists groups with filtering.

func (*GroupService) ListMyAssets

func (s *GroupService) ListMyAssets(ctx context.Context, tenantID string, userID shared.ID) ([]shared.ID, error)

ListMyAssets lists all assets the user can access through their group memberships.

func (*GroupService) ListUserGroups

func (s *GroupService) ListUserGroups(ctx context.Context, tenantID string, userID shared.ID) ([]*groupdom.GroupWithRole, error)

ListUserGroups lists all groups a user belongs to.

func (*GroupService) RemoveMember

func (s *GroupService) RemoveMember(ctx context.Context, groupID string, userID shared.ID, actx auditapp.AuditContext) error

RemoveMember removes a member from a group.

func (*GroupService) SetNotificationService

func (s *GroupService) SetNotificationService(ns *integration.NotificationService)

SetNotificationService sets the notification service for GroupService. This is used for late-binding when integration.NotificationService is initialized after GroupService.

func (*GroupService) UnassignAsset

func (s *GroupService) UnassignAsset(ctx context.Context, input UnassignAssetInput, actx auditapp.AuditContext) error

UnassignAsset removes an asset from a group.

func (*GroupService) UnassignPermissionSet

func (s *GroupService) UnassignPermissionSet(ctx context.Context, groupID, permissionSetID string, actx auditapp.AuditContext) error

UnassignPermissionSet removes a permission set from a group.

func (*GroupService) UpdateAssetOwnership

func (s *GroupService) UpdateAssetOwnership(ctx context.Context, input UpdateAssetOwnershipInput, actx auditapp.AuditContext) error

UpdateAssetOwnership updates the ownership type of an asset for a group.

func (*GroupService) UpdateGroup

func (s *GroupService) UpdateGroup(ctx context.Context, groupID string, input UpdateGroupInput, actx auditapp.AuditContext) (*groupdom.Group, error)

UpdateGroup updates a group.

func (*GroupService) UpdateMemberRole

UpdateMemberRole updates a member's role in a group.

type GroupServiceOption

type GroupServiceOption func(*GroupService)

GroupServiceOption is a functional option for GroupService.

func WithAccessControlRepository

func WithAccessControlRepository(repo accesscontroldom.Repository) GroupServiceOption

WithAccessControlRepository sets the access control repository.

func WithGroupAuditService

func WithGroupAuditService(auditService *auditapp.AuditService) GroupServiceOption

WithGroupAuditService sets the audit service for GroupService.

func WithPermissionSetRepository

func WithPermissionSetRepository(repo permissionsetdom.Repository) GroupServiceOption

WithPermissionSetRepository sets the permission set repository.

type GroupSyncService

type GroupSyncService struct {
	// contains filtered or unexported fields
}

GroupSyncService handles synchronization of groups from external providers such as GitHub Teams, GitLab Groups, Azure AD, and Okta.

func NewGroupSyncService

func NewGroupSyncService(groupRepo groupdom.Repository, log *logger.Logger) *GroupSyncService

NewGroupSyncService creates a new GroupSyncService.

func (*GroupSyncService) SyncAll

func (s *GroupSyncService) SyncAll(ctx context.Context, tenantID shared.ID) error

SyncAll synchronizes all configured external providers for a tenant. This is a placeholder implementation that iterates over groups with external sources and triggers sync for each unique provider.

func (*GroupSyncService) SyncFromProvider

func (s *GroupSyncService) SyncFromProvider(ctx context.Context, tenantID shared.ID, provider string, config map[string]interface{}) error

SyncFromProvider synchronizes groups from an external provider. This is a placeholder implementation. Actual provider integration (GitHub Teams, GitLab Groups, Azure AD, Okta) will be implemented as separate tasks.

The config parameter would contain provider-specific configuration such as:

  • GitHub: org name, API token
  • GitLab: group ID, API token
  • Azure AD: tenant ID, client credentials
  • Okta: domain, API token

type ListBundlesInput

type ListBundlesInput struct {
	TenantID string `json:"tenant_id" validate:"omitempty,uuid"`
	ToolID   string `json:"tool_id" validate:"omitempty,uuid"`
	Status   string `json:"status" validate:"omitempty,oneof=building ready failed expired"`
}

ListBundlesInput represents the input for listing bundles.

type ListGroupsInput

type ListGroupsInput struct {
	TenantID  string
	GroupType *string
	IsActive  *bool
	Search    string
	Limit     int
	Offset    int
}

ListGroupsInput represents the input for listing groups.

type ListGroupsOutput

type ListGroupsOutput struct {
	Groups     []*groupdom.Group
	TotalCount int64
}

ListGroupsOutput represents the output for listing groups.

type ListOverridesInput

type ListOverridesInput struct {
	TenantID      string `json:"tenant_id" validate:"omitempty,uuid"`
	ToolID        string `json:"tool_id" validate:"omitempty,uuid"`
	AssetGroupID  string `json:"asset_group_id" validate:"omitempty,uuid"`
	ScanProfileID string `json:"scan_profile_id" validate:"omitempty,uuid"`
	Enabled       *bool  `json:"enabled"`
	Page          int    `json:"page"`
	PerPage       int    `json:"per_page"`
}

ListOverridesInput represents the input for listing rule overrides.

type ListPermissionSetsInput

type ListPermissionSetsInput struct {
	TenantID      string
	IncludeSystem bool    // Include system permission sets
	SetType       *string // Filter by type
	IsActive      *bool
	Search        string
	Limit         int
	Offset        int
}

ListPermissionSetsInput represents the input for listing permission sets.

type ListPermissionSetsOutput

type ListPermissionSetsOutput struct {
	PermissionSets []*permissionsetdom.PermissionSet
	TotalCount     int64
}

ListPermissionSetsOutput represents the output for listing permission sets.

type ListRulesInput

type ListRulesInput struct {
	TenantID string   `json:"tenant_id" validate:"omitempty,uuid"`
	ToolID   string   `json:"tool_id" validate:"omitempty,uuid"`
	SourceID string   `json:"source_id" validate:"omitempty,uuid"`
	Severity string   `json:"severity" validate:"omitempty,oneof=critical high medium low info unknown"`
	Category string   `json:"category" validate:"max=100"`
	Tags     []string `json:"tags"`
	RuleIDs  []string `json:"rule_ids"`
	Search   string   `json:"search" validate:"max=255"`
	Page     int      `json:"page"`
	PerPage  int      `json:"per_page"`
}

ListRulesInput represents the input for listing rules.

type ListSourcesInput

type ListSourcesInput struct {
	TenantID          string `json:"tenant_id" validate:"omitempty,uuid"`
	ToolID            string `json:"tool_id" validate:"omitempty,uuid"`
	SourceType        string `json:"source_type" validate:"omitempty,oneof=git http local"`
	Enabled           *bool  `json:"enabled"`
	IsPlatformDefault *bool  `json:"is_platform_default"`
	SyncStatus        string `json:"sync_status" validate:"omitempty,oneof=pending syncing success failed"`
	Search            string `json:"search" validate:"max=255"`
	Page              int    `json:"page"`
	PerPage           int    `json:"per_page"`
}

ListSourcesInput represents the input for listing rule sources.

type MembershipCacheService

type MembershipCacheService struct {
	// contains filtered or unexported fields
}

MembershipCacheService is a thin Redis-backed wrapper around the tenant.Repository.GetMembership lookup that runs on EVERY tenant- scoped HTTP request via the RequireMembership middleware. Each authenticated dashboard load typically issues 30-50 API calls in quick succession, and the previous implementation hit the database once per call. The cache replaces those round trips with a Redis GET while still respecting the canonical membership lifecycle:

  • On miss → query tenant.Repository, store the result with a short TTL.
  • On suspend / reactivate / role change / member removal → TenantService calls Invalidate to drop the cached entry, so the next request fetches fresh state.
  • On Redis failure → fall through to the repository (the cache is best-effort, never load-bearing for correctness).

The cached value is intentionally minimal (membership ID, role, status, joined-at) to keep payload small and to avoid stale derived data. Downstream code only reads role + status from context, so a slim DTO is sufficient.

func NewMembershipCacheService

func NewMembershipCacheService(
	redisClient *redis.Client,
	repo tenant.Repository,
	log *logger.Logger,
) (*MembershipCacheService, error)

NewMembershipCacheService constructs a membership cache. If the redis client is unavailable for any reason the constructor returns an error and the caller should fall back to direct repository access (the wiring code in services.go does this gracefully).

func (*MembershipCacheService) GetMembership

func (s *MembershipCacheService) GetMembership(
	ctx context.Context, userID shared.ID, tenantID shared.ID,
) (*tenant.Membership, error)

GetMembership satisfies the middleware.MembershipReader interface. It returns a *tenant.Membership reconstructed from cached state on hit, or fetches from the repo + populates the cache on miss.

func (*MembershipCacheService) Invalidate

func (s *MembershipCacheService) Invalidate(
	ctx context.Context, tenantID, userID string,
)

Invalidate drops the cached entry for a (tenant, user) pair. Called from TenantService whenever a mutation could change role or status: SuspendMember, ReactivateMember, UpdateMembership (role change), DeleteMembership, AddMember (initial set).

func (*MembershipCacheService) InvalidateForTenant

func (s *MembershipCacheService) InvalidateForTenant(
	ctx context.Context, tenantID string,
)

InvalidateForTenant drops every cached membership in a tenant. Used when a role mass-update or tenant-wide rule change might have shifted the effective role of every member at once.

type PermissionCacheService

type PermissionCacheService struct {
	// contains filtered or unexported fields
}

PermissionCacheService provides cached access to user permissions. Permissions are cached in Redis with a short TTL for performance. On cache miss, permissions are fetched from the database.

Key format: user_perms:{tenant_id}:{user_id} → JSON array of permission strings Cache is invalidated when user's roles change.

func NewPermissionCacheService

func NewPermissionCacheService(
	redisClient *redis.Client,
	roleRepo roledom.Repository,
	versionSvc *PermissionVersionService,
	log *logger.Logger,
) (*PermissionCacheService, error)

NewPermissionCacheService creates a new permission cache service.

func (*PermissionCacheService) GetPermissions

func (s *PermissionCacheService) GetPermissions(ctx context.Context, tenantID, userID string) ([]string, error)

GetPermissions returns the permissions for a user. First checks Redis cache, then falls back to database.

func (*PermissionCacheService) GetPermissionsWithFallback

func (s *PermissionCacheService) GetPermissionsWithFallback(ctx context.Context, tenantID, userID string) ([]string, error)

GetPermissionsWithFallback returns permissions, falling back to database on any cache error. Use this when availability is more important than protecting the database.

func (*PermissionCacheService) HasAllPermissions

func (s *PermissionCacheService) HasAllPermissions(ctx context.Context, tenantID, userID string, permissions ...string) (bool, error)

HasAllPermissions checks if a user has all of the specified permissions.

func (*PermissionCacheService) HasAnyPermission

func (s *PermissionCacheService) HasAnyPermission(ctx context.Context, tenantID, userID string, permissions ...string) (bool, error)

HasAnyPermission checks if a user has any of the specified permissions.

func (*PermissionCacheService) HasPermission

func (s *PermissionCacheService) HasPermission(ctx context.Context, tenantID, userID, permission string) (bool, error)

HasPermission checks if a user has a specific permission.

func (*PermissionCacheService) Invalidate

func (s *PermissionCacheService) Invalidate(ctx context.Context, tenantID, userID string)

Invalidate removes the cached permissions for a user. Called when roles are changed.

func (*PermissionCacheService) InvalidateForTenant

func (s *PermissionCacheService) InvalidateForTenant(ctx context.Context, tenantID string)

InvalidateForTenant removes cached permissions for all users in a tenant. Called when a role definition is updated and affects potentially all users.

func (*PermissionCacheService) InvalidateForUsers

func (s *PermissionCacheService) InvalidateForUsers(ctx context.Context, tenantID string, userIDs []string)

InvalidateForUsers removes cached permissions for multiple users. Called when a role definition is updated.

func (*PermissionCacheService) Refresh

func (s *PermissionCacheService) Refresh(ctx context.Context, tenantID, userID string) ([]string, error)

Refresh refreshes the cached permissions for a user. Forces a database fetch and updates the cache.

type PermissionService

type PermissionService struct {
	// contains filtered or unexported fields
}

PermissionService handles permission-related business operations.

func NewPermissionService

func NewPermissionService(
	permissionSetRepo permissionsetdom.Repository,
	log *logger.Logger,
	opts ...PermissionServiceOption,
) *PermissionService

NewPermissionService creates a new PermissionService.

func (*PermissionService) AddPermissionToSet

func (s *PermissionService) AddPermissionToSet(ctx context.Context, input AddPermissionToSetInput, actx auditapp.AuditContext) error

AddPermissionToSet adds a permission to a permission set.

func (*PermissionService) CreateGroupPermission

CreateGroupPermission creates a custom permission override for a group.

func (*PermissionService) CreatePermissionSet

CreatePermissionSet creates a new permission set.

func (*PermissionService) DeleteGroupPermission

func (s *PermissionService) DeleteGroupPermission(ctx context.Context, groupID, permissionID string, actx auditapp.AuditContext) error

DeleteGroupPermission removes a custom permission override from a group.

func (*PermissionService) DeletePermissionSet

func (s *PermissionService) DeletePermissionSet(ctx context.Context, permissionSetID string, actx auditapp.AuditContext) error

DeletePermissionSet deletes a permission set.

func (*PermissionService) GetPermissionSet

func (s *PermissionService) GetPermissionSet(ctx context.Context, permissionSetID string) (*permissionsetdom.PermissionSet, error)

GetPermissionSet retrieves a permission set by ID.

func (*PermissionService) GetPermissionSetWithItems

func (s *PermissionService) GetPermissionSetWithItems(ctx context.Context, permissionSetID string) (*permissionsetdom.PermissionSetWithItems, error)

GetPermissionSetWithItems retrieves a permission set with its items.

func (*PermissionService) HasAllPermissions

func (s *PermissionService) HasAllPermissions(ctx context.Context, tenantID string, userID shared.ID, perms ...permissiondom.Permission) (bool, error)

HasAllPermissions checks if a user has all of the specified permissions.

func (*PermissionService) HasAnyPermission

func (s *PermissionService) HasAnyPermission(ctx context.Context, tenantID string, userID shared.ID, perms ...permissiondom.Permission) (bool, error)

HasAnyPermission checks if a user has any of the specified permissions.

func (*PermissionService) HasPermission

func (s *PermissionService) HasPermission(ctx context.Context, tenantID string, userID shared.ID, perm permissiondom.Permission) (bool, error)

HasPermission checks if a user has a specific permission.

func (*PermissionService) ListGroupCustomPermissions

func (s *PermissionService) ListGroupCustomPermissions(ctx context.Context, groupID string) ([]*accesscontroldom.GroupPermission, error)

ListGroupCustomPermissions lists custom permissions for a group.

func (*PermissionService) ListPermissionSets

ListPermissionSets lists permission sets with filtering.

func (*PermissionService) RemovePermissionFromSet

func (s *PermissionService) RemovePermissionFromSet(ctx context.Context, permissionSetID, permissionID string, actx auditapp.AuditContext) error

RemovePermissionFromSet removes a permission from a permission set.

func (*PermissionService) ResolveGroupPermissions

func (s *PermissionService) ResolveGroupPermissions(ctx context.Context, groupID string) ([]permissiondom.Permission, error)

ResolveGroupPermissions resolves all effective permissions for a group.

func (*PermissionService) ResolveUserPermissions

func (s *PermissionService) ResolveUserPermissions(ctx context.Context, tenantID string, userID shared.ID) ([]permissiondom.Permission, error)

ResolveUserPermissions resolves all effective permissions for a user.

func (*PermissionService) ResolveUserPermissionsWithCount

func (s *PermissionService) ResolveUserPermissionsWithCount(ctx context.Context, tenantID string, userID shared.ID) ([]permissiondom.Permission, int, error)

ResolveUserPermissionsWithCount resolves all effective permissions for a user and returns the group count.

func (*PermissionService) UpdatePermissionSet

func (s *PermissionService) UpdatePermissionSet(ctx context.Context, permissionSetID string, input UpdatePermissionSetInput, actx auditapp.AuditContext) (*permissionsetdom.PermissionSet, error)

UpdatePermissionSet updates a permission set.

type PermissionServiceOption

type PermissionServiceOption func(*PermissionService)

PermissionServiceOption is a functional option for PermissionService.

func WithPermissionAccessControlRepository

func WithPermissionAccessControlRepository(repo accesscontroldom.Repository) PermissionServiceOption

WithPermissionAccessControlRepository sets the access control repository.

func WithPermissionAuditService

func WithPermissionAuditService(auditService *auditapp.AuditService) PermissionServiceOption

WithPermissionAuditService sets the audit service for PermissionService.

func WithPermissionGroupRepository

func WithPermissionGroupRepository(repo groupdom.Repository) PermissionServiceOption

WithPermissionGroupRepository sets the group repository.

type PermissionVersionService

type PermissionVersionService struct {
	// contains filtered or unexported fields
}

PermissionVersionService manages permission version tracking in Redis. Version is incremented whenever a user's permissions change (role assigned/removed). This enables real-time permission synchronization without embedding permissions in JWT.

Key format: perm_ver:{tenant_id}:{user_id} → integer version When admin changes user's roles, the version is incremented. JWT contains the version at token generation time. If JWT version != Redis version, permissions are stale.

func NewPermissionVersionService

func NewPermissionVersionService(redisClient *redis.Client, log *logger.Logger) *PermissionVersionService

NewPermissionVersionService creates a new permission version service.

func (*PermissionVersionService) Delete

func (s *PermissionVersionService) Delete(ctx context.Context, tenantID, userID string) error

Delete removes the permission version for a user. Called when user is removed from tenant.

func (*PermissionVersionService) EnsureVersion

func (s *PermissionVersionService) EnsureVersion(ctx context.Context, tenantID, userID string) int

EnsureVersion ensures a version exists for the user, initializing to 1 if not. Returns the current version (either existing or newly initialized).

func (*PermissionVersionService) Get

func (s *PermissionVersionService) Get(ctx context.Context, tenantID, userID string) int

Get returns the current permission version for a user. Returns 1 if no version is set (new user).

func (*PermissionVersionService) Increment

func (s *PermissionVersionService) Increment(ctx context.Context, tenantID, userID string) int

Increment atomically increments the permission version for a user. Called when roles are assigned, removed, or modified. Returns the new version number.

func (*PermissionVersionService) IncrementForUsers

func (s *PermissionVersionService) IncrementForUsers(ctx context.Context, tenantID string, userIDs []string)

IncrementForUsers increments permission version for multiple users. Used when a role definition is updated (affects all users with that role).

func (*PermissionVersionService) Set

func (s *PermissionVersionService) Set(ctx context.Context, tenantID, userID string, version int) error

Set sets the permission version for a user to a specific value. Used during token generation to include current version in JWT.

type RoleService

type RoleService struct {
	// contains filtered or unexported fields
}

RoleService handles role-related business operations.

func NewRoleService

func NewRoleService(
	roleRepo roledom.Repository,
	permissionRepo roledom.PermissionRepository,
	log *logger.Logger,
	opts ...RoleServiceOption,
) *RoleService

NewRoleService creates a new RoleService.

func (*RoleService) AssignRole

func (s *RoleService) AssignRole(ctx context.Context, input AssignRoleInput, assignedBy string, actx auditapp.AuditContext) error

AssignRole assigns a role to a user.

func (*RoleService) BulkAssignRoleToUsers

func (s *RoleService) BulkAssignRoleToUsers(ctx context.Context, input BulkAssignRoleToUsersInput, assignedBy string, actx auditapp.AuditContext) (*BulkAssignRoleToUsersResult, error)

BulkAssignRoleToUsers assigns a role to multiple users at once.

func (*RoleService) CountUsersWithRole

func (s *RoleService) CountUsersWithRole(ctx context.Context, roleID string) (int, error)

CountUsersWithRole returns the count of users with a specific role.

func (*RoleService) CreateRole

func (s *RoleService) CreateRole(ctx context.Context, input CreateRoleInput, createdBy string, actx auditapp.AuditContext) (*roledom.Role, error)

CreateRole creates a new custom role for a tenant.

func (*RoleService) DeleteRole

func (s *RoleService) DeleteRole(ctx context.Context, roleID string, actx auditapp.AuditContext) error

DeleteRole deletes a role.

func (*RoleService) GetRole

func (s *RoleService) GetRole(ctx context.Context, roleID string) (*roledom.Role, error)

GetRole retrieves a role by ID.

func (*RoleService) GetRoleBySlug

func (s *RoleService) GetRoleBySlug(ctx context.Context, tenantID *string, slug string) (*roledom.Role, error)

GetRoleBySlug retrieves a role by slug.

func (*RoleService) GetUserPermissions

func (s *RoleService) GetUserPermissions(ctx context.Context, tenantID, userID string) ([]string, error)

GetUserPermissions returns all permissions for a user (UNION of all roles).

func (*RoleService) GetUserRoles

func (s *RoleService) GetUserRoles(ctx context.Context, tenantID, userID string) ([]*roledom.Role, error)

GetUserRoles returns all roles for a user in a tenant.

func (*RoleService) GetUsersRoles

func (s *RoleService) GetUsersRoles(
	ctx context.Context, tenantID string, userIDs []string,
) (map[string][]*roledom.Role, error)

GetUsersRoles returns all roles for multiple users in ONE round trip. Used by the member list endpoint to avoid the N+1 enrichment loop. Invalid user ID strings are silently dropped — the caller is the member list which can't have invalid IDs by construction (they come from the same DB), and the contract is "best effort" to keep the list endpoint resilient.

func (*RoleService) HasFullDataAccess

func (s *RoleService) HasFullDataAccess(ctx context.Context, tenantID, userID string) (bool, error)

HasFullDataAccess checks if user has full data access.

func (*RoleService) HasPermission

func (s *RoleService) HasPermission(ctx context.Context, tenantID, userID, permission string) (bool, error)

HasPermission checks if a user has a specific permission.

func (*RoleService) ListModulesWithPermissions

func (s *RoleService) ListModulesWithPermissions(ctx context.Context) ([]*roledom.Module, error)

ListModulesWithPermissions returns all modules with their permissions.

func (*RoleService) ListPermissions

func (s *RoleService) ListPermissions(ctx context.Context) ([]*roledom.Permission, error)

ListPermissions returns all permissions.

func (*RoleService) ListRoleMembers

func (s *RoleService) ListRoleMembers(ctx context.Context, tenantID, roleID string) ([]*roledom.UserRole, error)

ListRoleMembers returns all users who have a specific role.

func (*RoleService) ListRolesForTenant

func (s *RoleService) ListRolesForTenant(ctx context.Context, tenantID string) ([]*roledom.Role, error)

ListRolesForTenant returns all roles available for a tenant.

func (*RoleService) ListSystemRoles

func (s *RoleService) ListSystemRoles(ctx context.Context) ([]*roledom.Role, error)

ListSystemRoles returns only system roles.

func (*RoleService) RemoveRole

func (s *RoleService) RemoveRole(ctx context.Context, tenantID, userID, roleID string, actx auditapp.AuditContext) error

RemoveRole removes a role from a user.

func (*RoleService) SetUserRoles

func (s *RoleService) SetUserRoles(ctx context.Context, input SetUserRolesInput, assignedBy string, actx auditapp.AuditContext) error

SetUserRoles replaces all roles for a user.

func (*RoleService) UpdateRole

func (s *RoleService) UpdateRole(ctx context.Context, roleID string, input UpdateRoleInput, actx auditapp.AuditContext) (*roledom.Role, error)

UpdateRole updates a role.

type RoleServiceOption

type RoleServiceOption func(*RoleService)

RoleServiceOption is a functional option for RoleService.

func WithRoleAuditService

func WithRoleAuditService(auditService *auditapp.AuditService) RoleServiceOption

WithRoleAuditService sets the audit service for RoleService.

func WithRolePermissionCacheService

func WithRolePermissionCacheService(svc *PermissionCacheService) RoleServiceOption

WithRolePermissionCacheService sets the permission cache service. This enables permission cache invalidation when roles change.

func WithRolePermissionVersionService

func WithRolePermissionVersionService(svc *PermissionVersionService) RoleServiceOption

WithRolePermissionVersionService sets the permission version service. This enables real-time permission synchronization when roles change.

type RuleService

type RuleService struct {
	// contains filtered or unexported fields
}

RuleService handles rule management business operations.

func NewRuleService

func NewRuleService(
	sourceRepo ruledom.SourceRepository,
	ruleRepo ruledom.RuleRepository,
	bundleRepo ruledom.BundleRepository,
	overrideRepo ruledom.OverrideRepository,
	syncHistoryRepo ruledom.SyncHistoryRepository,
	auditService *auditapp.AuditService,
	log *logger.Logger,
) *RuleService

NewRuleService creates a new RuleService.

func (*RuleService) CleanupExpiredBundles

func (s *RuleService) CleanupExpiredBundles(ctx context.Context) (int64, error)

CleanupExpiredBundles deletes all expired bundles.

func (*RuleService) CompleteBundle

func (s *RuleService) CompleteBundle(ctx context.Context, input CompleteBundleInput) (*ruledom.Bundle, error)

CompleteBundle marks a bundle build as completed successfully.

func (*RuleService) CountRulesBySource

func (s *RuleService) CountRulesBySource(ctx context.Context, sourceID string) (int, error)

CountRulesBySource counts rules for a source.

func (*RuleService) CreateBundle

func (s *RuleService) CreateBundle(ctx context.Context, input CreateBundleInput) (*ruledom.Bundle, error)

CreateBundle creates a new rule bundle (starts building).

func (*RuleService) CreateOverride

func (s *RuleService) CreateOverride(ctx context.Context, input CreateOverrideInput) (*ruledom.Override, error)

CreateOverride creates a new rule override.

func (*RuleService) CreateSource

func (s *RuleService) CreateSource(ctx context.Context, input CreateSourceInput) (*ruledom.Source, error)

CreateSource creates a new rule source.

func (*RuleService) DeleteBundle

func (s *RuleService) DeleteBundle(ctx context.Context, bundleID string) error

DeleteBundle deletes a bundle.

func (*RuleService) DeleteOverride

func (s *RuleService) DeleteOverride(ctx context.Context, tenantID, overrideID string) error

DeleteOverride deletes a rule override.

func (*RuleService) DeleteSource

func (s *RuleService) DeleteSource(ctx context.Context, tenantID, sourceID string) error

DeleteSource deletes a rule source and its associated rules.

func (*RuleService) DisableSource

func (s *RuleService) DisableSource(ctx context.Context, tenantID, sourceID string) (*ruledom.Source, error)

DisableSource disables a rule source.

func (*RuleService) EnableSource

func (s *RuleService) EnableSource(ctx context.Context, tenantID, sourceID string) (*ruledom.Source, error)

EnableSource enables a rule source.

func (*RuleService) FailBundle

func (s *RuleService) FailBundle(ctx context.Context, bundleID, errorMessage string) (*ruledom.Bundle, error)

FailBundle marks a bundle build as failed.

func (*RuleService) GetBundleByID

func (s *RuleService) GetBundleByID(ctx context.Context, bundleID string) (*ruledom.Bundle, error)

GetBundleByID retrieves a bundle by ID.

func (*RuleService) GetLatestBundle

func (s *RuleService) GetLatestBundle(ctx context.Context, tenantID, toolID string) (*ruledom.Bundle, error)

GetLatestBundle retrieves the latest ready bundle for a tenant and tool.

func (*RuleService) GetOverride

func (s *RuleService) GetOverride(ctx context.Context, overrideID string) (*ruledom.Override, error)

GetOverride retrieves an override by ID.

func (*RuleService) GetOverrideByTenantAndID

func (s *RuleService) GetOverrideByTenantAndID(ctx context.Context, tenantID, overrideID string) (*ruledom.Override, error)

GetOverrideByTenantAndID retrieves an override by tenant and ID.

func (*RuleService) GetRule

func (s *RuleService) GetRule(ctx context.Context, ruleID string) (*ruledom.Rule, error)

GetRule retrieves a rule by ID.

func (*RuleService) GetSource

func (s *RuleService) GetSource(ctx context.Context, sourceID string) (*ruledom.Source, error)

GetSource retrieves a rule source by ID.

func (*RuleService) GetSourceByTenantAndID

func (s *RuleService) GetSourceByTenantAndID(ctx context.Context, tenantID, sourceID string) (*ruledom.Source, error)

GetSourceByTenantAndID retrieves a rule source by tenant and ID.

func (*RuleService) GetSyncHistory

func (s *RuleService) GetSyncHistory(ctx context.Context, sourceID string, limit int) ([]*ruledom.SyncHistory, error)

GetSyncHistory lists sync history for a source.

func (*RuleService) ListActiveOverridesForTool

func (s *RuleService) ListActiveOverridesForTool(ctx context.Context, tenantID string, toolID *string) ([]*ruledom.Override, error)

ListActiveOverridesForTool lists all active (non-expired) overrides for a tenant and tool.

func (*RuleService) ListBundles

func (s *RuleService) ListBundles(ctx context.Context, input ListBundlesInput) ([]*ruledom.Bundle, error)

ListBundles lists bundles with filters.

func (*RuleService) ListOverrides

ListOverrides lists rule overrides with filters.

func (*RuleService) ListRules

ListRules lists rules with filters.

func (*RuleService) ListRulesBySource

func (s *RuleService) ListRulesBySource(ctx context.Context, sourceID string) ([]*ruledom.Rule, error)

ListRulesBySource lists all rules for a source.

func (*RuleService) ListSources

ListSources lists rule sources with filters.

func (*RuleService) ListSourcesNeedingSync

func (s *RuleService) ListSourcesNeedingSync(ctx context.Context, limit int) ([]*ruledom.Source, error)

ListSourcesNeedingSync lists sources that need synchronization.

func (*RuleService) RecordSyncResult

func (s *RuleService) RecordSyncResult(ctx context.Context, sourceID string, result *SyncResult) error

RecordSyncResult records the result of a source sync operation.

func (*RuleService) UpdateOverride

func (s *RuleService) UpdateOverride(ctx context.Context, input UpdateOverrideInput) (*ruledom.Override, error)

UpdateOverride updates a rule override.

func (*RuleService) UpdateSource

func (s *RuleService) UpdateSource(ctx context.Context, input UpdateSourceInput) (*ruledom.Source, error)

UpdateSource updates a rule source.

func (*RuleService) UpsertRulesFromSync

func (s *RuleService) UpsertRulesFromSync(ctx context.Context, rules []*ruledom.Rule) error

UpsertRulesFromSync upserts rules from a sync operation.

type SetUserRolesInput

type SetUserRolesInput struct {
	TenantID string   `json:"-"`
	UserID   string   `json:"user_id" validate:"required,uuid"`
	RoleIDs  []string `json:"role_ids" validate:"required,min=1"`
}

SetUserRolesInput represents the input for setting user roles.

type SyncResult

type SyncResult struct {
	Status         ruledom.SyncStatus
	RulesAdded     int
	RulesUpdated   int
	RulesRemoved   int
	Duration       time.Duration
	ErrorMessage   string
	ErrorDetails   map[string]any
	PreviousHash   string
	NewContentHash string
}

SyncResult represents the result of a sync operation.

type SyncSourceInput

type SyncSourceInput struct {
	TenantID string `json:"tenant_id" validate:"required,uuid"`
	SourceID string `json:"source_id" validate:"required,uuid"`
}

SyncSourceInput represents the input for syncing a rule source.

type UnassignAssetInput

type UnassignAssetInput struct {
	GroupID string `json:"-"`
	AssetID string `json:"-"`
}

UnassignAssetInput represents the input for removing an asset from a group.

type UpdateAssetOwnershipInput

type UpdateAssetOwnershipInput struct {
	GroupID       string `json:"-"`
	AssetID       string `json:"-"`
	OwnershipType string `json:"ownership_type" validate:"required,oneof=primary secondary stakeholder informed"`
}

UpdateAssetOwnershipInput represents the input for updating asset ownership type.

type UpdateGroupInput

type UpdateGroupInput struct {
	Name               *string                      `json:"name" validate:"omitempty,min=2,max=100"`
	Slug               *string                      `json:"slug" validate:"omitempty,min=2,max=100,slug"`
	Description        *string                      `json:"description" validate:"omitempty,max=500"`
	Settings           *groupdom.GroupSettings      `json:"settings,omitempty"`
	NotificationConfig *groupdom.NotificationConfig `json:"notification_config,omitempty"`
	IsActive           *bool                        `json:"is_active,omitempty"`
}

UpdateGroupInput represents the input for updating a group.

type UpdateGroupMemberRoleInput

type UpdateGroupMemberRoleInput struct {
	GroupID string    `json:"-"`
	UserID  shared.ID `json:"-"`
	Role    string    `json:"role" validate:"required,oneof=owner lead member"`
}

UpdateMemberRoleInput represents the input for updating a member's role.

type UpdateOverrideInput

type UpdateOverrideInput struct {
	TenantID         string  `json:"tenant_id" validate:"required,uuid"`
	OverrideID       string  `json:"override_id" validate:"required,uuid"`
	RulePattern      string  `json:"rule_pattern" validate:"omitempty,min=1,max=500"`
	IsPattern        *bool   `json:"is_pattern"`
	Enabled          *bool   `json:"enabled"`
	SeverityOverride string  `json:"severity_override" validate:"omitempty,oneof=critical high medium low info"`
	AssetGroupID     string  `json:"asset_group_id" validate:"omitempty,uuid"`
	ScanProfileID    string  `json:"scan_profile_id" validate:"omitempty,uuid"`
	Reason           string  `json:"reason" validate:"max=1000"`
	ExpiresAt        *string `json:"expires_at"` // RFC3339 format, null to remove
}

UpdateOverrideInput represents the input for updating a rule override.

type UpdatePermissionSetInput

type UpdatePermissionSetInput struct {
	Name        *string `json:"name" validate:"omitempty,min=2,max=100"`
	Description *string `json:"description" validate:"omitempty,max=500"`
	IsActive    *bool   `json:"is_active,omitempty"`
}

UpdatePermissionSetInput represents the input for updating a permission set.

type UpdateRoleInput

type UpdateRoleInput struct {
	Name              *string  `json:"name" validate:"omitempty,min=2,max=100"`
	Description       *string  `json:"description" validate:"omitempty,max=500"`
	HierarchyLevel    *int     `json:"hierarchy_level" validate:"omitempty,min=0,max=100"`
	HasFullDataAccess *bool    `json:"has_full_data_access"`
	Permissions       []string `json:"permissions,omitempty"`
}

UpdateRoleInput represents the input for updating a role.

type UpdateSourceInput

type UpdateSourceInput struct {
	TenantID            string `json:"tenant_id" validate:"required,uuid"`
	SourceID            string `json:"source_id" validate:"required,uuid"`
	Name                string `json:"name" validate:"min=1,max=255"`
	Description         string `json:"description" validate:"max=1000"`
	Config              []byte `json:"config"`
	CredentialsID       string `json:"credentials_id" validate:"omitempty,uuid"`
	SyncEnabled         *bool  `json:"sync_enabled"`
	SyncIntervalMinutes int    `json:"sync_interval_minutes" validate:"omitempty,min=5,max=10080"`
	Priority            int    `json:"priority" validate:"omitempty,min=0,max=1000"`
	Enabled             *bool  `json:"enabled"`
}

UpdateSourceInput represents the input for updating a rule source.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL