@greenarmor/ges-core
Advanced tools
| import type { GovernanceRecord, GovernanceVerificationResult, GovernanceSystemType, GovernanceRiskLevel, ApprovalDecision, EvidenceRef, EvidenceType, EvidenceSourceSystem } from "../types/index.js"; | ||
| export declare function loadGovernanceRecords(projectPath: string): GovernanceRecord[]; | ||
| export declare function saveGovernanceRecords(projectPath: string, records: GovernanceRecord[]): void; | ||
| export declare function generateGovernanceId(): string; | ||
| export declare function generateEvidenceId(): string; | ||
| export interface CreateGovernanceRecordInput { | ||
| system_name: string; | ||
| system_description?: string; | ||
| system_type?: GovernanceSystemType; | ||
| system_version?: string; | ||
| risk_level?: GovernanceRiskLevel; | ||
| created_by?: string; | ||
| } | ||
| export declare function createGovernanceRecord(opts: CreateGovernanceRecordInput): GovernanceRecord; | ||
| export declare function addGovernanceRecord(projectPath: string, record: GovernanceRecord): GovernanceRecord; | ||
| export declare function updateGovernanceRecord(projectPath: string, id: string, updates: Partial<GovernanceRecord>, updatedBy?: string): GovernanceRecord | null; | ||
| export declare function findGovernanceRecord(projectPath: string, id: string): GovernanceRecord | null; | ||
| export declare function setGovernanceApproval(projectPath: string, id: string, approval: ApprovalDecision, updatedBy?: string): GovernanceRecord | null; | ||
| export declare function addGovernanceEvidence(projectPath: string, id: string, evidence: EvidenceRef, updatedBy?: string): GovernanceRecord | null; | ||
| export declare function createEvidenceRef(opts: { | ||
| type: EvidenceType; | ||
| title: string; | ||
| source_system: EvidenceSourceSystem; | ||
| reference: string; | ||
| location_description: string; | ||
| added_by: string; | ||
| }): EvidenceRef; | ||
| export declare function deleteGovernanceRecord(projectPath: string, id: string): boolean; | ||
| export declare function setGovernanceRiskAssessment(projectPath: string, id: string, riskAssessment: import("../types/index.js").RiskAssessmentRef, updatedBy?: string): GovernanceRecord | null; | ||
| export declare function setGovernancePolicyBasis(projectPath: string, id: string, policyBasis: import("../types/index.js").PolicyBasisRef, updatedBy?: string): GovernanceRecord | null; | ||
| export declare function setGovernanceReviewCycle(projectPath: string, id: string, reviewCycle: import("../types/index.js").ReviewCycle, updatedBy?: string): GovernanceRecord | null; | ||
| export declare function setGovernanceDataInventory(projectPath: string, id: string, dataInventory: import("../types/index.js").GovernanceDataInventory, updatedBy?: string): GovernanceRecord | null; | ||
| export declare function setGovernanceComplianceLinks(projectPath: string, id: string, compliance: import("../types/index.js").GovernanceComplianceLinks, updatedBy?: string): GovernanceRecord | null; | ||
| export declare function setGovernanceCommittee(projectPath: string, id: string, committee: import("../types/index.js").CommitteeApprovalRef, updatedBy?: string): GovernanceRecord | null; | ||
| export declare function verifyGovernanceRecord(record: GovernanceRecord): GovernanceVerificationResult; | ||
| export declare function verifyAllGovernanceRecords(projectPath: string): GovernanceVerificationResult[]; |
| import * as fs from "node:fs"; | ||
| import * as path from "node:path"; | ||
| const GOVERNANCE_FILE = "governance-records.json"; | ||
| function recordsPath(projectPath) { | ||
| return path.join(projectPath, ".ges", GOVERNANCE_FILE); | ||
| } | ||
| export function loadGovernanceRecords(projectPath) { | ||
| const rPath = recordsPath(projectPath); | ||
| try { | ||
| const raw = fs.readFileSync(rPath, "utf-8"); | ||
| const data = JSON.parse(raw); | ||
| return Array.isArray(data) ? data : []; | ||
| } | ||
| catch { | ||
| return []; | ||
| } | ||
| } | ||
| export function saveGovernanceRecords(projectPath, records) { | ||
| const gesDir = path.join(projectPath, ".ges"); | ||
| if (!fs.existsSync(gesDir)) { | ||
| fs.mkdirSync(gesDir, { recursive: true }); | ||
| } | ||
| fs.writeFileSync(recordsPath(projectPath), JSON.stringify(records, null, 2), "utf-8"); | ||
| } | ||
| let govCounter = 0; | ||
| export function generateGovernanceId() { | ||
| govCounter++; | ||
| return `gov-${Date.now()}-${govCounter}`; | ||
| } | ||
| let evidenceCounter = 0; | ||
| export function generateEvidenceId() { | ||
| evidenceCounter++; | ||
| return `evidence-${Date.now()}-${evidenceCounter}`; | ||
| } | ||
| export function createGovernanceRecord(opts) { | ||
| const now = new Date().toISOString(); | ||
| const id = generateGovernanceId(); | ||
| return { | ||
| id, | ||
| system_name: opts.system_name, | ||
| system_description: opts.system_description || "", | ||
| system_type: opts.system_type || "ai-system", | ||
| system_version: opts.system_version || "", | ||
| status: "draft", | ||
| risk_level: opts.risk_level || "medium", | ||
| approval: null, | ||
| risk_assessment: null, | ||
| policy_basis: null, | ||
| committee: null, | ||
| evidence: [], | ||
| review_cycle: null, | ||
| data_inventory: null, | ||
| compliance: null, | ||
| created_at: now, | ||
| created_by: opts.created_by || "system", | ||
| updated_at: now, | ||
| updated_by: opts.created_by || "system", | ||
| record_version: 1, | ||
| }; | ||
| } | ||
| export function addGovernanceRecord(projectPath, record) { | ||
| const records = loadGovernanceRecords(projectPath); | ||
| records.push(record); | ||
| saveGovernanceRecords(projectPath, records); | ||
| return record; | ||
| } | ||
| export function updateGovernanceRecord(projectPath, id, updates, updatedBy) { | ||
| const records = loadGovernanceRecords(projectPath); | ||
| const idx = records.findIndex(r => r.id === id); | ||
| if (idx === -1) | ||
| return null; | ||
| const now = new Date().toISOString(); | ||
| records[idx] = { | ||
| ...records[idx], | ||
| ...updates, | ||
| updated_at: now, | ||
| updated_by: updatedBy || records[idx].updated_by, | ||
| record_version: records[idx].record_version + 1, | ||
| }; | ||
| saveGovernanceRecords(projectPath, records); | ||
| return records[idx]; | ||
| } | ||
| export function findGovernanceRecord(projectPath, id) { | ||
| const records = loadGovernanceRecords(projectPath); | ||
| return records.find(r => r.id === id || r.system_name.toLowerCase() === id.toLowerCase()) || null; | ||
| } | ||
| export function setGovernanceApproval(projectPath, id, approval, updatedBy) { | ||
| const record = findGovernanceRecord(projectPath, id); | ||
| if (!record) | ||
| return null; | ||
| const newStatus = approval.decision === "approved" ? "approved" : approval.decision === "rejected" ? "rejected" : "conditional"; | ||
| return updateGovernanceRecord(projectPath, record.id, { approval, status: newStatus }, updatedBy); | ||
| } | ||
| export function addGovernanceEvidence(projectPath, id, evidence, updatedBy) { | ||
| const record = findGovernanceRecord(projectPath, id); | ||
| if (!record) | ||
| return null; | ||
| const evidenceList = [...record.evidence, evidence]; | ||
| return updateGovernanceRecord(projectPath, record.id, { evidence: evidenceList }, updatedBy); | ||
| } | ||
| export function createEvidenceRef(opts) { | ||
| return { | ||
| id: generateEvidenceId(), | ||
| type: opts.type, | ||
| title: opts.title, | ||
| source_system: opts.source_system, | ||
| reference: opts.reference, | ||
| location_description: opts.location_description, | ||
| added_by: opts.added_by, | ||
| added_at: new Date().toISOString(), | ||
| }; | ||
| } | ||
| export function deleteGovernanceRecord(projectPath, id) { | ||
| const records = loadGovernanceRecords(projectPath); | ||
| const filtered = records.filter(r => r.id !== id && r.system_name.toLowerCase() !== id.toLowerCase()); | ||
| if (filtered.length === records.length) | ||
| return false; | ||
| saveGovernanceRecords(projectPath, filtered); | ||
| return true; | ||
| } | ||
| export function setGovernanceRiskAssessment(projectPath, id, riskAssessment, updatedBy) { | ||
| const record = findGovernanceRecord(projectPath, id); | ||
| if (!record) | ||
| return null; | ||
| return updateGovernanceRecord(projectPath, record.id, { risk_assessment: riskAssessment }, updatedBy); | ||
| } | ||
| export function setGovernancePolicyBasis(projectPath, id, policyBasis, updatedBy) { | ||
| const record = findGovernanceRecord(projectPath, id); | ||
| if (!record) | ||
| return null; | ||
| return updateGovernanceRecord(projectPath, record.id, { policy_basis: policyBasis }, updatedBy); | ||
| } | ||
| export function setGovernanceReviewCycle(projectPath, id, reviewCycle, updatedBy) { | ||
| const record = findGovernanceRecord(projectPath, id); | ||
| if (!record) | ||
| return null; | ||
| return updateGovernanceRecord(projectPath, record.id, { review_cycle: reviewCycle }, updatedBy); | ||
| } | ||
| export function setGovernanceDataInventory(projectPath, id, dataInventory, updatedBy) { | ||
| const record = findGovernanceRecord(projectPath, id); | ||
| if (!record) | ||
| return null; | ||
| return updateGovernanceRecord(projectPath, record.id, { data_inventory: dataInventory }, updatedBy); | ||
| } | ||
| export function setGovernanceComplianceLinks(projectPath, id, compliance, updatedBy) { | ||
| const record = findGovernanceRecord(projectPath, id); | ||
| if (!record) | ||
| return null; | ||
| return updateGovernanceRecord(projectPath, record.id, { compliance }, updatedBy); | ||
| } | ||
| export function setGovernanceCommittee(projectPath, id, committee, updatedBy) { | ||
| const record = findGovernanceRecord(projectPath, id); | ||
| if (!record) | ||
| return null; | ||
| return updateGovernanceRecord(projectPath, record.id, { committee }, updatedBy); | ||
| } | ||
| export function verifyGovernanceRecord(record) { | ||
| const issues = []; | ||
| const warnings = []; | ||
| const hasApproval = record.approval !== null; | ||
| const hasRiskAssessment = record.risk_assessment !== null; | ||
| const hasPolicyBasis = record.policy_basis !== null; | ||
| const hasEvidence = record.evidence.length > 0; | ||
| const hasReviewCycle = record.review_cycle !== null; | ||
| const hasDataInventory = record.data_inventory !== null; | ||
| const hasComplianceLinks = record.compliance !== null; | ||
| if (!hasApproval) | ||
| issues.push("No approval decision recorded"); | ||
| if (!hasRiskAssessment) | ||
| issues.push("No risk assessment linked"); | ||
| if (!hasPolicyBasis) | ||
| issues.push("No policy basis documented"); | ||
| if (!hasEvidence) | ||
| issues.push("No evidence references attached"); | ||
| if (!hasReviewCycle) | ||
| warnings.push("No review cycle defined — continuous compliance not monitored"); | ||
| if (!hasDataInventory) | ||
| warnings.push("No data inventory — personal data categories undocumented"); | ||
| if (!hasComplianceLinks) | ||
| warnings.push("No compliance framework links mapped"); | ||
| let approvalStatus = "none"; | ||
| let daysUntilExpiry = null; | ||
| if (hasApproval && record.approval) { | ||
| const now = new Date(); | ||
| if (record.approval.valid_until) { | ||
| const expiry = new Date(record.approval.valid_until); | ||
| daysUntilExpiry = Math.ceil((expiry.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)); | ||
| if (daysUntilExpiry < 0) { | ||
| approvalStatus = "expired"; | ||
| issues.push(`Approval expired on ${record.approval.valid_until}`); | ||
| } | ||
| else { | ||
| approvalStatus = "valid"; | ||
| if (daysUntilExpiry <= 30) { | ||
| warnings.push(`Approval expires in ${daysUntilExpiry} days (${record.approval.valid_until})`); | ||
| } | ||
| } | ||
| } | ||
| else { | ||
| approvalStatus = "valid"; | ||
| } | ||
| if (record.status === "pending-review" || record.status === "draft") { | ||
| approvalStatus = "pending"; | ||
| } | ||
| } | ||
| const isCurrent = approvalStatus === "valid" && | ||
| (record.review_cycle === null || new Date(record.review_cycle.next_review) >= new Date()); | ||
| const valid = issues.length === 0 && hasApproval && hasRiskAssessment && hasEvidence; | ||
| return { | ||
| record_id: record.id, | ||
| system_name: record.system_name, | ||
| valid, | ||
| issues, | ||
| warnings, | ||
| completeness: { | ||
| has_approval: hasApproval, | ||
| has_risk_assessment: hasRiskAssessment, | ||
| has_policy_basis: hasPolicyBasis, | ||
| has_evidence: hasEvidence, | ||
| has_review_cycle: hasReviewCycle, | ||
| has_data_inventory: hasDataInventory, | ||
| has_compliance_links: hasComplianceLinks, | ||
| evidence_count: record.evidence.length, | ||
| is_current: isCurrent, | ||
| }, | ||
| approval_status: approvalStatus, | ||
| days_until_expiry: daysUntilExpiry, | ||
| }; | ||
| } | ||
| export function verifyAllGovernanceRecords(projectPath) { | ||
| return loadGovernanceRecords(projectPath).map(verifyGovernanceRecord); | ||
| } |
@@ -12,2 +12,4 @@ import type { ActivityLogEntry, ActivityAction, ActivityStatus } from "../types/index.js"; | ||
| details?: ActivityLogEntry["details"]; | ||
| actor_name?: string; | ||
| actor_role?: string; | ||
| }): ActivityLogEntry; | ||
@@ -21,2 +23,4 @@ export declare function recordActivity(projectPath: string, opts: { | ||
| details?: ActivityLogEntry["details"]; | ||
| actor_name?: string; | ||
| actor_role?: string; | ||
| }): void; |
@@ -42,2 +42,4 @@ import * as fs from "node:fs"; | ||
| source: opts.source, | ||
| actor_name: opts.actor_name, | ||
| actor_role: opts.actor_role, | ||
| action: opts.action, | ||
@@ -44,0 +46,0 @@ title: opts.title, |
@@ -32,2 +32,4 @@ import type { FixHistoryEntry, ControlStatus, SeverityLevel } from "../types/index.js"; | ||
| source: "cli" | "mcp"; | ||
| actor_name?: string; | ||
| actor_role?: string; | ||
| dry_run: boolean; | ||
@@ -34,0 +36,0 @@ finding: FindingLike; |
@@ -43,2 +43,4 @@ import * as fs from "node:fs"; | ||
| source: opts.source, | ||
| actor_name: opts.actor_name, | ||
| actor_role: opts.actor_role, | ||
| dry_run: opts.dry_run, | ||
@@ -45,0 +47,0 @@ finding: { |
+1
-0
@@ -8,1 +8,2 @@ export * from "./types/index.js"; | ||
| export * from "./recommendations/index.js"; | ||
| export * from "./governance/index.js"; |
+1
-0
@@ -8,1 +8,2 @@ export * from "./types/index.js"; | ||
| export * from "./recommendations/index.js"; | ||
| export * from "./governance/index.js"; |
+124
-0
@@ -162,2 +162,4 @@ export type ProjectType = "saas" | "ai-application" | "mcp-server" | "blockchain" | "wallet" | "government-system" | "healthcare-system" | "event-platform" | "photo-storage-platform" | "vulnerability-scanner" | "generic-web-application" | "api-backend" | "mobile-application"; | ||
| source: "cli" | "mcp"; | ||
| actor_name?: string; | ||
| actor_role?: string; | ||
| dry_run: boolean; | ||
@@ -201,2 +203,4 @@ finding: { | ||
| source: "cli" | "mcp"; | ||
| actor_name?: string; | ||
| actor_role?: string; | ||
| action: ActivityAction; | ||
@@ -218,1 +222,121 @@ title: string; | ||
| } | ||
| export type GovernanceSystemType = "ai-system" | "application" | "data-process" | "api" | "model" | "infrastructure" | "third-party-service"; | ||
| export type GovernanceStatus = "draft" | "pending-review" | "approved" | "rejected" | "conditional" | "expired" | "revoked"; | ||
| export type GovernanceRiskLevel = "low" | "medium" | "high" | "critical"; | ||
| export type EvidenceType = "document" | "ticket" | "meeting-record" | "email" | "report" | "certificate" | "log" | "dashboard" | "contract" | "other"; | ||
| export type EvidenceSourceSystem = "jira" | "servicenow" | "confluence" | "sharepoint" | "grc-platform" | "email" | "git" | "file" | "url" | "other"; | ||
| export interface EvidenceRef { | ||
| id: string; | ||
| type: EvidenceType; | ||
| title: string; | ||
| source_system: EvidenceSourceSystem; | ||
| reference: string; | ||
| location_description: string; | ||
| added_by: string; | ||
| added_at: string; | ||
| } | ||
| export interface ApprovalDecision { | ||
| approver_name: string; | ||
| approver_role: string; | ||
| approver_email: string; | ||
| approval_authority: string; | ||
| decision: "approved" | "rejected" | "conditional"; | ||
| decision_date: string; | ||
| valid_from: string; | ||
| valid_until: string | null; | ||
| conditions: string[]; | ||
| rationale: string; | ||
| } | ||
| export interface RiskAssessmentRef { | ||
| id: string; | ||
| assessor: string; | ||
| assessment_date: string; | ||
| methodology: string; | ||
| risk_score: string; | ||
| identified_risks: string[]; | ||
| residual_risk: string; | ||
| mitigation_measures: string[]; | ||
| evidence: EvidenceRef[]; | ||
| } | ||
| export interface PolicyBasisRef { | ||
| policy_id: string; | ||
| policy_name: string; | ||
| version: string; | ||
| clauses: string[]; | ||
| standard: string; | ||
| evidence: EvidenceRef[]; | ||
| } | ||
| export interface CommitteeApprovalRef { | ||
| committee_name: string; | ||
| meeting_date: string; | ||
| meeting_reference: string; | ||
| attendees: string[]; | ||
| decision_summary: string; | ||
| evidence: EvidenceRef[]; | ||
| } | ||
| export interface ReviewCycleEntry { | ||
| date: string; | ||
| reviewer: string; | ||
| outcome: "continued" | "modified" | "revoked" | "expired"; | ||
| notes: string; | ||
| } | ||
| export interface ReviewCycle { | ||
| frequency: "quarterly" | "semi-annual" | "annual" | "biennial"; | ||
| last_review: string; | ||
| next_review: string; | ||
| review_history: ReviewCycleEntry[]; | ||
| } | ||
| export interface GovernanceDataInventory { | ||
| personal_data_categories: string[]; | ||
| processing_purposes: string[]; | ||
| data_subjects: string[]; | ||
| cross_border_transfers: string[]; | ||
| retention_period: string; | ||
| } | ||
| export interface GovernanceComplianceLinks { | ||
| frameworks: string[]; | ||
| controls_satisfied: string[]; | ||
| control_pack_ids: string[]; | ||
| } | ||
| export interface GovernanceRecord { | ||
| id: string; | ||
| system_name: string; | ||
| system_description: string; | ||
| system_type: GovernanceSystemType; | ||
| system_version: string; | ||
| status: GovernanceStatus; | ||
| risk_level: GovernanceRiskLevel; | ||
| approval: ApprovalDecision | null; | ||
| risk_assessment: RiskAssessmentRef | null; | ||
| policy_basis: PolicyBasisRef | null; | ||
| committee: CommitteeApprovalRef | null; | ||
| evidence: EvidenceRef[]; | ||
| review_cycle: ReviewCycle | null; | ||
| data_inventory: GovernanceDataInventory | null; | ||
| compliance: GovernanceComplianceLinks | null; | ||
| created_at: string; | ||
| created_by: string; | ||
| updated_at: string; | ||
| updated_by: string; | ||
| record_version: number; | ||
| } | ||
| export interface GovernanceVerificationResult { | ||
| record_id: string; | ||
| system_name: string; | ||
| valid: boolean; | ||
| issues: string[]; | ||
| warnings: string[]; | ||
| completeness: { | ||
| has_approval: boolean; | ||
| has_risk_assessment: boolean; | ||
| has_policy_basis: boolean; | ||
| has_evidence: boolean; | ||
| has_review_cycle: boolean; | ||
| has_data_inventory: boolean; | ||
| has_compliance_links: boolean; | ||
| evidence_count: number; | ||
| is_current: boolean; | ||
| }; | ||
| approval_status: "valid" | "expired" | "pending" | "none"; | ||
| days_until_expiry: number | null; | ||
| } |
+1
-1
@@ -27,3 +27,3 @@ { | ||
| "types": "./dist/index.d.ts", | ||
| "version": "1.3.0", | ||
| "version": "1.4.0", | ||
| "scripts": { | ||
@@ -30,0 +30,0 @@ "build": "tsc", |
81729
25.81%21
10.53%2004
25.25%