# frozen_string_literal: true require_relative "../github/base" module Neetob class CLI module Code class Audit < Github::Base attr_accessor :sandbox, :apps def initialize(apps, sandbox = false) super() @apps = apps @sandbox = sandbox end def run matching_apps = find_all_matching_apps_or_repos(apps, :github, sandbox) ui.info( "\nListing apps and their tables that doesn't have uuid as primary key type:-", print_to_audit_log: false) has_found_tables_without_uuid = false data = [] matching_apps.each do |app| begin db_schema = Base64.decode64(client.contents(app, path: "./db/schema.rb").content) tables_without_uuid = find_tables_without_uuid_as_primary_key(db_schema).compact if !tables_without_uuid.nil? has_found_tables_without_uuid = true print_app_and_tables(app, tables_without_uuid) end unique_email_index_result = verify_unique_email_index(db_schema) data << { tables_without_uuid:, unique_email_index_result: } rescue Octokit::NotFound ui.error("There is no \"db/schema.rb\" file in the \"#{app}\" app.") data << { error: "There is no \"db/schema.rb\" file in the \"#{app}\" app." } rescue StandardError => e ExceptionHandler.new(e).process end end ui.info( "No apps found to have tables without uuid as primary key type", print_to_audit_log: false) if !has_found_tables_without_uuid if Thread.current[:audit_mode] data end end private def find_tables_without_uuid_as_primary_key(db_schema) create_table_regex = /create_table.*?,\s*force:\s*:cascade\s*do\s*\|t\|/ db_schema.scan(create_table_regex).map do |create_table_line| !create_table_line.include?("id: :uuid") ? create_table_line.scan(/"([^"]+)"/).flatten.first : nil end end def verify_unique_email_index(db_schema) index_pattern = / create_table\s+"users".*? ( t\.index\s+\[ \s*"email"\s* \],\s+ name:\s*"index_users_on_email" | t\.index\s+\[ \s*"email"\s*,\s*"organization_id"\s* \],\s+ name:\s*"index_users_on_email_and_organization_id"\s*,\s+ unique:\s*true ) /mx index_pattern_matched = db_schema.match(index_pattern) if index_pattern_matched ui.success("\nUsers are indexed properly", print_to_audit_log: false) else ui.error("\nUsers are not indexed", print_to_audit_log: false) end index_pattern_matched end def print_app_and_tables(app, tables) ui.info("\n#{app}:-", print_to_audit_log: false) tables.each do |table| ui.say(" ↳#{table}") end end end end end end