@greenarmor/ges-core 1.2.3 → 1.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,20 @@
1
+ import type { ActivityLogEntry, ActivityAction, ActivityStatus } from "../types/index.js";
2
+ export declare function loadActivityLog(projectPath: string): ActivityLogEntry[];
3
+ export declare function appendActivityLog(projectPath: string, entries: ActivityLogEntry[]): void;
4
+ export declare function clearActivityLog(projectPath: string): void;
5
+ export declare function createActivityLogEntry(opts: {
6
+ source: "cli" | "mcp";
7
+ action: ActivityAction;
8
+ title: string;
9
+ description: string;
10
+ status?: ActivityStatus;
11
+ details?: ActivityLogEntry["details"];
12
+ }): ActivityLogEntry;
13
+ export declare function recordActivity(projectPath: string, opts: {
14
+ source: "cli" | "mcp";
15
+ action: ActivityAction;
16
+ title: string;
17
+ description: string;
18
+ status?: ActivityStatus;
19
+ details?: ActivityLogEntry["details"];
20
+ }): void;
@@ -0,0 +1,57 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ export function loadActivityLog(projectPath) {
4
+ const logPath = path.join(projectPath, ".ges", "activity-log.json");
5
+ try {
6
+ const raw = fs.readFileSync(logPath, "utf-8");
7
+ const data = JSON.parse(raw);
8
+ return Array.isArray(data) ? data : [];
9
+ }
10
+ catch {
11
+ return [];
12
+ }
13
+ }
14
+ export function appendActivityLog(projectPath, entries) {
15
+ if (entries.length === 0)
16
+ return;
17
+ const gesDir = path.join(projectPath, ".ges");
18
+ if (!fs.existsSync(gesDir)) {
19
+ fs.mkdirSync(gesDir, { recursive: true });
20
+ }
21
+ const logPath = path.join(gesDir, "activity-log.json");
22
+ const existing = loadActivityLog(projectPath);
23
+ const updated = existing.concat(entries);
24
+ fs.writeFileSync(logPath, JSON.stringify(updated, null, 2), "utf-8");
25
+ }
26
+ export function clearActivityLog(projectPath) {
27
+ const logPath = path.join(projectPath, ".ges", "activity-log.json");
28
+ try {
29
+ fs.unlinkSync(logPath);
30
+ }
31
+ catch {
32
+ // ignore
33
+ }
34
+ }
35
+ let activityCounter = 0;
36
+ export function createActivityLogEntry(opts) {
37
+ activityCounter++;
38
+ return {
39
+ id: `activity-${Date.now()}-${activityCounter}`,
40
+ timestamp: new Date().toISOString(),
41
+ source: opts.source,
42
+ action: opts.action,
43
+ title: opts.title,
44
+ description: opts.description,
45
+ status: opts.status || "success",
46
+ details: opts.details || {},
47
+ };
48
+ }
49
+ export function recordActivity(projectPath, opts) {
50
+ const entry = createActivityLogEntry(opts);
51
+ try {
52
+ appendActivityLog(projectPath, [entry]);
53
+ }
54
+ catch {
55
+ // ignore persistence errors
56
+ }
57
+ }
@@ -0,0 +1,9 @@
1
+ import type { Control, ControlOverride, ControlStatus, ProjectConfig } from "../types/index.js";
2
+ export declare function loadControlsFromDisk(projectPath: string): Control[];
3
+ export declare function getInstalledPackIds(projectPath: string): Set<string>;
4
+ export declare function loadControlOverrides(projectPath: string): ControlOverride[];
5
+ export declare function saveControlOverride(projectPath: string, controlId: string, status: ControlStatus, reason: string): void;
6
+ export declare function applyOverridesToControls(controls: Control[], overrides: ControlOverride[]): Control[];
7
+ export declare function loadConfig(projectPath: string): ProjectConfig | null;
8
+ export declare function addFrameworkToConfig(projectPath: string, framework: string): boolean;
9
+ export declare function removeFrameworkFromConfig(projectPath: string, framework: string): boolean;
@@ -0,0 +1,145 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ const GES_DIR = ".ges";
4
+ const CONTROLS_DIR = "controls";
5
+ const CONFIG_FILE = "config.json";
6
+ const OVERRIDES_FILE = "control-overrides.json";
7
+ export function loadControlsFromDisk(projectPath) {
8
+ const controlsDir = path.join(projectPath, CONTROLS_DIR);
9
+ const result = [];
10
+ try {
11
+ const entries = fs.readdirSync(controlsDir, { withFileTypes: true });
12
+ for (const entry of entries) {
13
+ if (!entry.isDirectory())
14
+ continue;
15
+ const ctrlFile = path.join(controlsDir, entry.name, "controls.json");
16
+ if (!fs.existsSync(ctrlFile))
17
+ continue;
18
+ try {
19
+ const raw = fs.readFileSync(ctrlFile, "utf-8");
20
+ const parsed = JSON.parse(raw);
21
+ if (Array.isArray(parsed)) {
22
+ for (const ctrl of parsed) {
23
+ if (ctrl && typeof ctrl.id === "string") {
24
+ result.push(ctrl);
25
+ }
26
+ }
27
+ }
28
+ }
29
+ catch {
30
+ // skip malformed controls.json
31
+ }
32
+ }
33
+ }
34
+ catch {
35
+ // controls dir may not exist
36
+ }
37
+ return result;
38
+ }
39
+ export function getInstalledPackIds(projectPath) {
40
+ const ids = new Set();
41
+ const controlsDir = path.join(projectPath, CONTROLS_DIR);
42
+ try {
43
+ const entries = fs.readdirSync(controlsDir, { withFileTypes: true });
44
+ for (const entry of entries) {
45
+ if (entry.isDirectory()) {
46
+ const ctrlFile = path.join(controlsDir, entry.name, "controls.json");
47
+ if (fs.existsSync(ctrlFile)) {
48
+ ids.add(entry.name);
49
+ }
50
+ }
51
+ }
52
+ }
53
+ catch {
54
+ // controls dir may not exist
55
+ }
56
+ return ids;
57
+ }
58
+ export function loadControlOverrides(projectPath) {
59
+ const overridesPath = path.join(projectPath, GES_DIR, OVERRIDES_FILE);
60
+ try {
61
+ const raw = fs.readFileSync(overridesPath, "utf-8");
62
+ const parsed = JSON.parse(raw);
63
+ return Array.isArray(parsed) ? parsed : [];
64
+ }
65
+ catch {
66
+ return [];
67
+ }
68
+ }
69
+ export function saveControlOverride(projectPath, controlId, status, reason) {
70
+ const gesDir = path.join(projectPath, GES_DIR);
71
+ if (!fs.existsSync(gesDir)) {
72
+ fs.mkdirSync(gesDir, { recursive: true });
73
+ }
74
+ const overrides = loadControlOverrides(projectPath);
75
+ const existingIdx = overrides.findIndex(o => o.control_id === controlId);
76
+ const entry = { control_id: controlId, status, reason };
77
+ if (existingIdx >= 0) {
78
+ overrides[existingIdx] = entry;
79
+ }
80
+ else {
81
+ overrides.push(entry);
82
+ }
83
+ const overridesPath = path.join(gesDir, OVERRIDES_FILE);
84
+ fs.writeFileSync(overridesPath, JSON.stringify(overrides, null, 2), "utf-8");
85
+ }
86
+ export function applyOverridesToControls(controls, overrides) {
87
+ if (overrides.length === 0)
88
+ return controls;
89
+ return controls.map(control => {
90
+ const override = overrides.find(o => o.control_id === control.id);
91
+ if (!override)
92
+ return control;
93
+ return {
94
+ ...control,
95
+ status: override.status,
96
+ checks: control.checks.map(check => ({ ...check, status: override.status })),
97
+ };
98
+ });
99
+ }
100
+ export function loadConfig(projectPath) {
101
+ const configPath = path.join(projectPath, GES_DIR, CONFIG_FILE);
102
+ try {
103
+ const raw = fs.readFileSync(configPath, "utf-8");
104
+ return JSON.parse(raw);
105
+ }
106
+ catch {
107
+ return null;
108
+ }
109
+ }
110
+ export function addFrameworkToConfig(projectPath, framework) {
111
+ const configPath = path.join(projectPath, GES_DIR, CONFIG_FILE);
112
+ try {
113
+ const raw = fs.readFileSync(configPath, "utf-8");
114
+ const config = JSON.parse(raw);
115
+ if (!config.frameworks)
116
+ config.frameworks = [];
117
+ const fwLower = new Set(config.frameworks.map((f) => f.toLowerCase()));
118
+ if (fwLower.has(framework.toLowerCase()))
119
+ return false;
120
+ config.frameworks.push(framework);
121
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
122
+ return true;
123
+ }
124
+ catch {
125
+ return false;
126
+ }
127
+ }
128
+ export function removeFrameworkFromConfig(projectPath, framework) {
129
+ const configPath = path.join(projectPath, GES_DIR, CONFIG_FILE);
130
+ try {
131
+ const raw = fs.readFileSync(configPath, "utf-8");
132
+ const config = JSON.parse(raw);
133
+ if (!config.frameworks)
134
+ return false;
135
+ const before = config.frameworks.length;
136
+ config.frameworks = config.frameworks.filter((f) => f.toLowerCase() !== framework.toLowerCase());
137
+ if (config.frameworks.length === before)
138
+ return false;
139
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
140
+ return true;
141
+ }
142
+ catch {
143
+ return false;
144
+ }
145
+ }
package/dist/index.d.ts CHANGED
@@ -2,3 +2,5 @@ export * from "./types/index.js";
2
2
  export * from "./schemas/index.js";
3
3
  export * from "./constants/index.js";
4
4
  export * from "./fix-history/index.js";
5
+ export * from "./controls/index.js";
6
+ export * from "./activity-log/index.js";
package/dist/index.js CHANGED
@@ -2,3 +2,5 @@ export * from "./types/index.js";
2
2
  export * from "./schemas/index.js";
3
3
  export * from "./constants/index.js";
4
4
  export * from "./fix-history/index.js";
5
+ export * from "./controls/index.js";
6
+ export * from "./activity-log/index.js";
@@ -190,3 +190,25 @@ export interface FixHistoryEntry {
190
190
  severity_resolved: SeverityLevel;
191
191
  };
192
192
  }
193
+ export type ActivityAction = "init" | "audit" | "fix" | "policy_install" | "policy_remove" | "control_override" | "implement_control" | "score" | "scan" | "validate" | "generate" | "hooks_install" | "hooks_uninstall" | "dashboard_start" | "badge_generate";
194
+ export type ActivityStatus = "success" | "partial" | "failed" | "info";
195
+ export interface ActivityLogEntry {
196
+ id: string;
197
+ timestamp: string;
198
+ source: "cli" | "mcp";
199
+ action: ActivityAction;
200
+ title: string;
201
+ description: string;
202
+ status: ActivityStatus;
203
+ details: {
204
+ packs_affected?: string[];
205
+ controls_affected?: string[];
206
+ files_created?: string[];
207
+ files_modified?: string[];
208
+ findings_count?: number;
209
+ fixes_applied?: number;
210
+ score?: number;
211
+ frameworks_added?: string[];
212
+ [key: string]: unknown;
213
+ };
214
+ }
package/package.json CHANGED
@@ -24,7 +24,7 @@
24
24
  "name": "@greenarmor/ges-core",
25
25
  "type": "module",
26
26
  "types": "./dist/index.d.ts",
27
- "version": "1.2.3",
27
+ "version": "1.2.5",
28
28
  "scripts": {
29
29
  "build": "tsc",
30
30
  "clean": "rm -rf dist tsconfig.tsbuildinfo",