AI Evidence Collection: Real Schema Implementation

Technical implementation guide using the actual Compliance Scorecard database schema with AI-powered evidence collection mapped to existing table structures.

Current Database Schema for Evidence Collection

assessment_events_questions

Primary table for storing control evidence and AI validation results

Core Evidence Fields:
  • control_id varchar(200) - Framework control identifier
  • control_evidence_source varchar(50) - Integration source
  • control_evidence_location varchar(255) - API endpoint/path
  • evidence_location text - JSON evidence data
  • evidence_location_type enum('file_path','text')
  • responsibility enum('msp','company','shared','tool')
AI Validation Fields:
  • selected_option_id varchar(20) - AI-selected answer
  • auditor_notes text - AI analysis notes
  • auditor_conformity_mark varchar(255) - met/not met
  • question_notes text - Additional AI insights
  • implementation_statement text - AI-generated

api_keys

Integration credentials for AI evidence collection sources

Integration Types:
  • type enum includes:
  • • 'connectwise' - RMM/PSA data
  • • 'auvik' - Network monitoring
  • • 'msgraph' - Microsoft 365
  • • 'ninja' - RMM platform
  • • 'huntress' - Security platform
  • • 'cybercns' - Security monitoring
Authentication Fields:
  • key varchar(255) - API key
  • secret text - API secret
  • access_token text - OAuth token
  • refresh_token text - Token refresh
  • expires_at timestamp - Token expiry

connector_client_mappings

Maps internal clients to external system identifiers for evidence collection

Mapping Fields:
  • client_id varchar(20) - Internal client
  • connector_client_id varchar(255) - External ID
  • type varchar(255) - Integration type
  • source_from_connector varchar(255) - Data source
Metadata Fields:
  • source_id_from_connector varchar(255)
  • client_name_from_connector varchar(255)
  • description_from_connector varchar(255)

AI Evidence Collection Implementation

SOC 2 CC6.1 - User Access Management

AI Enhancement: Real Schema Implementation

Using actual database tables to store AI-collected evidence with human oversight workflows.

where('assessment_event_id', $assessmentEventId)
            ->where('control_id', 'SOC2_CC6.1')
            ->first();

        // Get client's ConnectWise mapping
        $cwMapping = DB::table('connector_client_mappings')
            ->where('client_id', $clientId)
            ->where('type', 'connectwise')
            ->first();

        // Get API credentials
        $apiKey = DB::table('api_keys')
            ->where('client_id', $clientId)
            ->where('type', 'connectwise')
            ->first();

        // Collect user access data
        $cwApi = new ConnectWiseAPI($apiKey);
        $members = $cwApi->get("/company/companies/{$cwMapping->connector_client_id}/members");
        
        // AI Analysis of user access controls
        $aiAnalysis = $this->analyzeUserAccess($members);
        
        // Store evidence in existing schema
        DB::table('assessment_events_questions')
            ->where('id', $assessmentQuestion->id)
            ->update([
                'control_evidence_source' => 'connectwise',
                'control_evidence_location' => "/company/companies/{$cwMapping->connector_client_id}/members",
                'evidence_location' => json_encode([
                    'total_users' => count($members),
                    'active_users' => $aiAnalysis['active_count'],
                    'privileged_users' => $aiAnalysis['privileged_count'],
                    'last_access_review' => $aiAnalysis['last_review_date'],
                    'compliance_score' => $aiAnalysis['score'],
                    'raw_data' => $members
                ]),
                'evidence_location_type' => 'text',
                'responsibility' => 'tool',
                'selected_option_id' => $this->getOptionByScore($aiAnalysis['score']),
                'auditor_notes' => $aiAnalysis['summary'],
                'auditor_conformity_mark' => $aiAnalysis['score'] >= 85 ? 'met' : 'not met',
                'question_notes' => $aiAnalysis['recommendations']
            ]);

        return $aiAnalysis;
    }

    private function analyzeUserAccess($members) 
    {
        $ai = new OpenAIAnalyzer();
        
        $prompt = "Analyze this user access data for SOC 2 CC6.1 compliance:
        - Review user privileges and access levels
        - Check for segregation of duties
        - Identify inactive accounts
        - Assess access review processes
        
        Data: " . json_encode($members);
        
        $analysis = $ai->analyze($prompt);
        
        return [
            'active_count' => $this->countActiveUsers($members),
            'privileged_count' => $this->countPrivilegedUsers($members), 
            'last_review_date' => $this->getLastReviewDate($members),
            'score' => $this->calculateComplianceScore($analysis),
            'summary' => $analysis['summary'],
            'recommendations' => $analysis['recommendations'],
            'risks' => $analysis['identified_risks']
        ];
    }
}
?>

ISO 27001 A.8.1.1 - Asset Inventory

where('assessment_event_id', $assessmentEventId)
            ->where('control_id', 'ISO27001_A.8.1.1')
            ->first();

        // Collect from multiple sources in parallel
        $assets = collect();
        
        // ConnectWise - Hardware assets
        if ($cwMapping = $this->getClientMapping($clientId, 'connectwise')) {
            $cwAssets = $this->collectConnectWiseAssets($clientId, $cwMapping);
            $assets = $assets->merge($this->tagAssets($cwAssets, 'hardware', 'connectwise'));
        }
        
        // Auvik - Network devices  
        if ($auvikMapping = $this->getClientMapping($clientId, 'auvik')) {
            $networkAssets = $this->collectAuvikAssets($clientId, $auvikMapping);
            $assets = $assets->merge($this->tagAssets($networkAssets, 'network', 'auvik'));
        }
        
        // Microsoft Graph - Software/licenses
        if ($graphMapping = $this->getClientMapping($clientId, 'msgraph')) {
            $softwareAssets = $this->collectGraphAssets($clientId, $graphMapping);
            $assets = $assets->merge($this->tagAssets($softwareAssets, 'software', 'msgraph'));
        }

        // AI consolidation and analysis
        $aiAnalysis = $this->performAIAssetAnalysis($assets->toArray());
        
        // Update assessment question with consolidated evidence
        DB::table('assessment_events_questions')
            ->where('id', $assessmentQuestion->id)
            ->update([
                'control_evidence_source' => 'multiple', // connectwise,auvik,msgraph
                'control_evidence_location' => json_encode([
                    'connectwise' => '/company/configurations',
                    'auvik' => '/v1/inventory/device/info',
                    'msgraph' => '/v1.0/organization/{id}/applications'
                ]),
                'evidence_location' => json_encode([
                    'total_assets' => $assets->count(),
                    'asset_categories' => $aiAnalysis['categories'],
                    'coverage_score' => $aiAnalysis['coverage_score'],
                    'risk_assessment' => $aiAnalysis['risk_assessment'],
                    'consolidated_inventory' => $aiAnalysis['consolidated_assets'],
                    'collection_timestamp' => now()->toISOString()
                ]),
                'evidence_location_type' => 'text',
                'responsibility' => 'tool',
                'selected_option_id' => $this->getOptionByScore($aiAnalysis['coverage_score']),
                'auditor_notes' => $aiAnalysis['executive_summary'],
                'auditor_conformity_mark' => $aiAnalysis['coverage_score'] >= 90 ? 'met' : 'not met',
                'implementation_statement' => $this->generateImplementationStatement($aiAnalysis),
                'question_notes' => implode("\n", $aiAnalysis['recommendations'])
            ]);

        return $aiAnalysis;
    }

    private function performAIAssetAnalysis($assets) 
    {
        $ai = new OpenAIAnalyzer();
        
        return $ai->analyze([
            'task' => 'asset_inventory_analysis',
            'framework' => 'ISO27001_A.8.1.1',
            'data' => $assets,
            'requirements' => [
                'completeness_check',
                'categorization',
                'risk_assessment', 
                'compliance_scoring',
                'gap_identification'
            ]
        ]);
    }
}
?>

NIST CSF RS.RP - Incident Response

where('assessment_event_id', $assessmentEventId)
            ->where('control_id', 'NIST_CSF_RS.RP')
            ->first();

        // Collect incident data from service desk
        $incidents = $this->collectIncidentTickets($clientId, $startDate, $endDate);
        
        // Collect security alerts
        $securityAlerts = $this->collectSecurityAlerts($clientId, $startDate, $endDate);
        
        // AI analysis of incident response capability
        $aiAnalysis = $this->analyzeIncidentResponse([
            'incidents' => $incidents,
            'security_alerts' => $securityAlerts,
            'time_period' => ['start' => $startDate, 'end' => $endDate]
        ]);

        // Store comprehensive incident response evidence
        DB::table('assessment_events_questions')
            ->where('id', $assessmentQuestion->id)
            ->update([
                'control_evidence_source' => 'connectwise,huntress,cybercns',
                'control_evidence_location' => json_encode([
                    'incidents' => '/service/tickets',
                    'security_alerts' => '/api/alerts',
                    'response_metrics' => '/api/metrics'
                ]),
                'evidence_location' => json_encode([
                    'incident_count' => count($incidents),
                    'security_incident_count' => $aiAnalysis['security_incidents'],
                    'average_response_time' => $aiAnalysis['avg_response_time'],
                    'response_effectiveness' => $aiAnalysis['effectiveness_score'],
                    'process_maturity' => $aiAnalysis['maturity_level'],
                    'team_readiness' => $aiAnalysis['readiness_score'],
                    'detailed_analysis' => $aiAnalysis['detailed_breakdown']
                ]),
                'evidence_location_type' => 'text',
                'responsibility' => 'tool',
                'selected_option_id' => $this->getOptionByScore($aiAnalysis['overall_score']),
                'auditor_notes' => $aiAnalysis['executive_summary'],
                'auditor_conformity_mark' => $aiAnalysis['overall_score'] >= 80 ? 'met' : 'not met',
                'implementation_statement' => $this->generateNISTImplementationStatement($aiAnalysis),
                'question_notes' => $this->formatRecommendations($aiAnalysis['recommendations'])
            ]);

        return $aiAnalysis;
    }

    private function collectIncidentTickets($clientId, $startDate, $endDate) 
    {
        $cwMapping = $this->getClientMapping($clientId, 'connectwise');
        $apiKey = $this->getAPIKey($clientId, 'connectwise');
        
        $cwApi = new ConnectWiseAPI($apiKey);
        
        return $cwApi->get('/service/tickets', [
            'conditions' => "company/id={$cwMapping->connector_client_id} AND " .
                           "dateEntered >= [{$startDate}] AND dateEntered <= [{$endDate}] AND " .
                           "(summary CONTAINS 'security' OR summary CONTAINS 'incident' OR " .
                           "summary CONTAINS 'breach' OR priority/name = 'Critical')",
            'pageSize' => 1000
        ]);
    }

    private function analyzeIncidentResponse($data) 
    {
        $ai = new OpenAIAnalyzer();
        
        return $ai->analyze([
            'framework' => 'NIST_CSF_RS.RP',
            'task' => 'incident_response_analysis',
            'data' => $data,
            'analysis_requirements' => [
                'response_time_analysis',
                'process_effectiveness',
                'team_readiness_assessment',
                'process_maturity_evaluation',
                'compliance_scoring'
            ]
        ]);
    }
}
?>

Human-in-the-Loop AI Decision Workflows

Automated Evidence Collection
find($assessmentQuestionId);
        
        // AI collects and analyzes evidence
        $evidence = $this->collectEvidence($question);
        $aiScore = $this->calculateConfidenceScore($evidence);
        
        if ($aiScore >= 95) {
            // High confidence - auto-approve
            $this->updateQuestionWithEvidence($question, $evidence, 'auto_approved');
            $this->logDecision($question, 'auto_approved', $aiScore);
        } elseif ($aiScore >= 75) {
            // Medium confidence - queue for review
            $this->queueForHumanReview($question, $evidence, 'review_required');
            $this->notifyReviewer($question, $evidence);
        } else {
            // Low confidence - require human collection
            $this->flagForManualCollection($question, $evidence, 'manual_required');
            $this->notifyComplianceTeam($question);
        }
        
        return $aiScore;
    }
}
?>
Human Review Interface
// Frontend human review interface
class EvidenceReviewInterface {
    
    async loadPendingReviews() {
        const reviews = await api.get('/evidence/pending-review');
        
        reviews.forEach(review => {
            this.renderReviewCard({
                control: review.control_id,
                aiScore: review.ai_confidence,
                evidence: JSON.parse(review.evidence_location),
                aiNotes: review.auditor_notes,
                recommendation: review.ai_recommendation,
                onApprove: () => this.approveEvidence(review.id),
                onReject: () => this.rejectEvidence(review.id),
                onModify: () => this.modifyEvidence(review.id)
            });
        });
    }
    
    async approveEvidence(questionId) {
        await api.post(`/evidence/${questionId}/approve`, {
            human_reviewer: currentUser.id,
            review_decision: 'approved',
            review_timestamp: new Date()
        });
        
        this.updateQuestionStatus(questionId, 'human_approved');
    }
}