package main import ( "database/sql" "errors" "fmt" "log" "os" "strings" "github.com/oklog/ulid/v2" "github.com/spf13/cobra" "github.com/spf13/viper" ) var ( permissionRole string permissionResource string permissionAction string ) var permissionCmd = &cobra.Command{ Use: "permission", Short: "Manage permissions", Long: `Commands for managing permissions in the MCIAS system.`, } var listPermissionsCmd = &cobra.Command{ Use: "list", Short: "List all permissions", Long: `List all permissions in the MCIAS system.`, Run: func(cmd *cobra.Command, args []string) { listPermissions() }, } var grantPermissionCmd = &cobra.Command{ Use: "grant", Short: "Grant a permission to a role", Long: `Grant a permission to a role in the MCIAS system.`, Run: func(cmd *cobra.Command, args []string) { grantPermission() }, } var revokePermissionCmd = &cobra.Command{ Use: "revoke", Short: "Revoke a permission from a role", Long: `Revoke a permission from a role in the MCIAS system.`, Run: func(cmd *cobra.Command, args []string) { revokePermission() }, } // nolint:gochecknoinits // This is a standard pattern in Cobra applications func init() { rootCmd.AddCommand(permissionCmd) permissionCmd.AddCommand(listPermissionsCmd) permissionCmd.AddCommand(grantPermissionCmd) permissionCmd.AddCommand(revokePermissionCmd) grantPermissionCmd.Flags().StringVar(&permissionRole, "role", "", "Name of the role to grant the permission to") grantPermissionCmd.Flags().StringVar(&permissionResource, "resource", "", "Resource for the permission") grantPermissionCmd.Flags().StringVar(&permissionAction, "action", "", "Action for the permission") if err := grantPermissionCmd.MarkFlagRequired("role"); err != nil { fmt.Fprintf(os.Stderr, "Error marking role flag as required: %v\n", err) } if err := grantPermissionCmd.MarkFlagRequired("resource"); err != nil { fmt.Fprintf(os.Stderr, "Error marking resource flag as required: %v\n", err) } if err := grantPermissionCmd.MarkFlagRequired("action"); err != nil { fmt.Fprintf(os.Stderr, "Error marking action flag as required: %v\n", err) } revokePermissionCmd.Flags().StringVar(&permissionRole, "role", "", "Name of the role to revoke the permission from") revokePermissionCmd.Flags().StringVar(&permissionResource, "resource", "", "Resource for the permission") revokePermissionCmd.Flags().StringVar(&permissionAction, "action", "", "Action for the permission") if err := revokePermissionCmd.MarkFlagRequired("role"); err != nil { fmt.Fprintf(os.Stderr, "Error marking role flag as required: %v\n", err) } if err := revokePermissionCmd.MarkFlagRequired("resource"); err != nil { fmt.Fprintf(os.Stderr, "Error marking resource flag as required: %v\n", err) } if err := revokePermissionCmd.MarkFlagRequired("action"); err != nil { fmt.Fprintf(os.Stderr, "Error marking action flag as required: %v\n", err) } } func listPermissions() { dbPath := viper.GetString("db") logger := log.New(os.Stdout, "MCIAS: ", log.LstdFlags) db, err := sql.Open("sqlite3", dbPath) if err != nil { logger.Fatalf("Failed to open database: %v", err) } defer db.Close() rows, err := db.Query("SELECT id, resource, action, description FROM permissions ORDER BY resource, action") if err != nil { logger.Fatalf("Failed to query permissions: %v", err) } defer rows.Close() fmt.Printf("%-24s %-20s %-15s %-30s\n", "ID", "RESOURCE", "ACTION", "DESCRIPTION") fmt.Println(strings.Repeat("-", 90)) for rows.Next() { var id, resource, action, description string if scanErr := rows.Scan(&id, &resource, &action, &description); scanErr != nil { logger.Fatalf("Failed to scan permission row: %v", scanErr) } fmt.Printf("%-24s %-20s %-15s %-30s\n", id, resource, action, description) } if rowErr := rows.Err(); rowErr != nil { logger.Fatalf("Error iterating permission rows: %v", rowErr) } } func grantPermission() { dbPath := viper.GetString("db") logger := log.New(os.Stdout, "MCIAS: ", log.LstdFlags) db, err := sql.Open("sqlite3", dbPath) if err != nil { logger.Fatalf("Failed to open database: %v", err) } defer db.Close() // Get role ID var roleID string err = db.QueryRow("SELECT id FROM roles WHERE role = ?", permissionRole).Scan(&roleID) if err != nil { if errors.Is(err, sql.ErrNoRows) { logger.Fatalf("Role %s not found", permissionRole) } logger.Fatalf("Failed to get role ID: %v", err) } // Get permission ID var permissionID string err = db.QueryRow("SELECT id FROM permissions WHERE resource = ? AND action = ?", permissionResource, permissionAction).Scan(&permissionID) if err != nil { if errors.Is(err, sql.ErrNoRows) { logger.Fatalf("Permission with resource '%s' and action '%s' not found", permissionResource, permissionAction) } logger.Fatalf("Failed to get permission ID: %v", err) } // Check if role already has this permission var count int err = db.QueryRow("SELECT COUNT(*) FROM role_permissions WHERE rid = ? AND pid = ?", roleID, permissionID).Scan(&count) if err != nil { logger.Fatalf("Failed to check if role has permission: %v", err) } if count > 0 { logger.Fatalf("Role %s already has permission %s:%s", permissionRole, permissionResource, permissionAction) } // Generate a new ID for the role-permission relationship id := ulid.Make().String() // Grant permission to role _, err = db.Exec("INSERT INTO role_permissions (id, rid, pid) VALUES (?, ?, ?)", id, roleID, permissionID) if err != nil { logger.Fatalf("Failed to grant permission: %v", err) } fmt.Printf("Permission %s:%s granted to role %s successfully\n", permissionResource, permissionAction, permissionRole) } func revokePermission() { dbPath := viper.GetString("db") logger := log.New(os.Stdout, "MCIAS: ", log.LstdFlags) db, err := sql.Open("sqlite3", dbPath) if err != nil { logger.Fatalf("Failed to open database: %v", err) } defer db.Close() // Get role ID var roleID string err = db.QueryRow("SELECT id FROM roles WHERE role = ?", permissionRole).Scan(&roleID) if err != nil { if errors.Is(err, sql.ErrNoRows) { logger.Fatalf("Role %s not found", permissionRole) } logger.Fatalf("Failed to get role ID: %v", err) } // Get permission ID var permissionID string err = db.QueryRow("SELECT id FROM permissions WHERE resource = ? AND action = ?", permissionResource, permissionAction).Scan(&permissionID) if err != nil { if errors.Is(err, sql.ErrNoRows) { logger.Fatalf("Permission with resource '%s' and action '%s' not found", permissionResource, permissionAction) } logger.Fatalf("Failed to get permission ID: %v", err) } // Check if role has this permission var count int err = db.QueryRow("SELECT COUNT(*) FROM role_permissions WHERE rid = ? AND pid = ?", roleID, permissionID).Scan(&count) if err != nil { logger.Fatalf("Failed to check if role has permission: %v", err) } if count == 0 { logger.Fatalf("Role %s does not have permission %s:%s", permissionRole, permissionResource, permissionAction) } // Revoke permission from role _, err = db.Exec("DELETE FROM role_permissions WHERE rid = ? AND pid = ?", roleID, permissionID) if err != nil { logger.Fatalf("Failed to revoke permission: %v", err) } fmt.Printf("Permission %s:%s revoked from role %s successfully\n", permissionResource, permissionAction, permissionRole) }