@grc-claw/integration-marketplace 1.0.0
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.
- package/dist/IntegrationMarketplace.d.ts +32 -0
- package/dist/IntegrationMarketplace.js +165 -0
- package/dist/connectors/AWSCloudTrailConnector.d.ts +12 -0
- package/dist/connectors/AWSCloudTrailConnector.js +77 -0
- package/dist/connectors/AWSIAMConnector.d.ts +12 -0
- package/dist/connectors/AWSIAMConnector.js +90 -0
- package/dist/connectors/AWSS3Connector.d.ts +12 -0
- package/dist/connectors/AWSS3Connector.js +112 -0
- package/dist/connectors/AzureADConnector.d.ts +12 -0
- package/dist/connectors/AzureADConnector.js +115 -0
- package/dist/connectors/AzureSentinelConnector.d.ts +12 -0
- package/dist/connectors/AzureSentinelConnector.js +88 -0
- package/dist/connectors/BambooHRConnector.d.ts +12 -0
- package/dist/connectors/BambooHRConnector.js +84 -0
- package/dist/connectors/CrowdStrikeConnector.d.ts +12 -0
- package/dist/connectors/CrowdStrikeConnector.js +86 -0
- package/dist/connectors/DatadogConnector.d.ts +12 -0
- package/dist/connectors/DatadogConnector.js +110 -0
- package/dist/connectors/DockerHubConnector.d.ts +12 -0
- package/dist/connectors/DockerHubConnector.js +80 -0
- package/dist/connectors/GCPIAMConnector.d.ts +12 -0
- package/dist/connectors/GCPIAMConnector.js +98 -0
- package/dist/connectors/GCPSCCConnector.d.ts +12 -0
- package/dist/connectors/GCPSCCConnector.js +94 -0
- package/dist/connectors/GitHubActionsConnector.d.ts +12 -0
- package/dist/connectors/GitHubActionsConnector.js +104 -0
- package/dist/connectors/GitHubConnector.d.ts +12 -0
- package/dist/connectors/GitHubConnector.js +135 -0
- package/dist/connectors/GitLabConnector.d.ts +12 -0
- package/dist/connectors/GitLabConnector.js +101 -0
- package/dist/connectors/HubSpotConnector.d.ts +12 -0
- package/dist/connectors/HubSpotConnector.js +77 -0
- package/dist/connectors/JiraConnector.d.ts +12 -0
- package/dist/connectors/JiraConnector.js +103 -0
- package/dist/connectors/KubernetesConnector.d.ts +12 -0
- package/dist/connectors/KubernetesConnector.js +109 -0
- package/dist/connectors/OktaConnector.d.ts +12 -0
- package/dist/connectors/OktaConnector.js +123 -0
- package/dist/connectors/PagerDutyConnector.d.ts +12 -0
- package/dist/connectors/PagerDutyConnector.js +106 -0
- package/dist/connectors/QualysConnector.d.ts +12 -0
- package/dist/connectors/QualysConnector.js +96 -0
- package/dist/connectors/SalesforceConnector.d.ts +12 -0
- package/dist/connectors/SalesforceConnector.js +91 -0
- package/dist/connectors/SlackConnector.d.ts +12 -0
- package/dist/connectors/SlackConnector.js +109 -0
- package/dist/connectors/SnowflakeConnector.d.ts +12 -0
- package/dist/connectors/SnowflakeConnector.js +105 -0
- package/dist/connectors/SnykConnector.d.ts +12 -0
- package/dist/connectors/SnykConnector.js +84 -0
- package/dist/connectors/TerraformCloudConnector.d.ts +12 -0
- package/dist/connectors/TerraformCloudConnector.js +106 -0
- package/dist/connectors/index.d.ts +25 -0
- package/dist/connectors/index.js +25 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +3 -0
- package/dist/index.test.d.ts +1 -0
- package/dist/index.test.js +138 -0
- package/dist/types.d.ts +57 -0
- package/dist/types.js +8 -0
- package/package.json +26 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { IntegrationConnector, ConnectorConfig, EvidenceArtifact, IntegrationCategory, ComplianceFramework, MarketplaceStats } from "./types.js";
|
|
2
|
+
export interface CollectionJob {
|
|
3
|
+
id: string;
|
|
4
|
+
connectorId: string;
|
|
5
|
+
startedAt: string;
|
|
6
|
+
completedAt?: string;
|
|
7
|
+
status: "running" | "completed" | "failed";
|
|
8
|
+
artifacts: EvidenceArtifact[];
|
|
9
|
+
error?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare class IntegrationMarketplace {
|
|
12
|
+
private registrations;
|
|
13
|
+
private configs;
|
|
14
|
+
private jobs;
|
|
15
|
+
constructor();
|
|
16
|
+
private registerBuiltinConnectors;
|
|
17
|
+
registerConnector(connector: IntegrationConnector): void;
|
|
18
|
+
unregisterConnector(connectorId: string): boolean;
|
|
19
|
+
enableConnector(connectorId: string): void;
|
|
20
|
+
disableConnector(connectorId: string): void;
|
|
21
|
+
setConfig(connectorId: string, config: ConnectorConfig): void;
|
|
22
|
+
getConnector(connectorId: string): IntegrationConnector | undefined;
|
|
23
|
+
getEnabledConnectors(): IntegrationConnector[];
|
|
24
|
+
getConnectorsByCategory(category: IntegrationCategory): IntegrationConnector[];
|
|
25
|
+
getConnectorsByFramework(framework: ComplianceFramework): IntegrationConnector[];
|
|
26
|
+
testAllConnections(): Promise<Map<string, boolean>>;
|
|
27
|
+
collectFromConnector(connectorId: string): Promise<CollectionJob>;
|
|
28
|
+
collectAll(): Promise<CollectionJob[]>;
|
|
29
|
+
getStats(): MarketplaceStats;
|
|
30
|
+
getJobs(): CollectionJob[];
|
|
31
|
+
getRecentJobs(limit?: number): CollectionJob[];
|
|
32
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { GitHubConnector, GitLabConnector, AWSIAMConnector, AWSS3Connector, AWSCloudTrailConnector, AzureADConnector, AzureSentinelConnector, GCPIAMConnector, GCPSCCConnector, OktaConnector, JiraConnector, SlackConnector, PagerDutyConnector, SnowflakeConnector, DatadogConnector, CrowdStrikeConnector, QualysConnector, SnykConnector, TerraformCloudConnector, GitHubActionsConnector, DockerHubConnector, KubernetesConnector, SalesforceConnector, HubSpotConnector, BambooHRConnector, } from "./connectors/index.js";
|
|
2
|
+
export class IntegrationMarketplace {
|
|
3
|
+
registrations = new Map();
|
|
4
|
+
configs = new Map();
|
|
5
|
+
jobs = [];
|
|
6
|
+
constructor() {
|
|
7
|
+
this.registerBuiltinConnectors();
|
|
8
|
+
}
|
|
9
|
+
registerBuiltinConnectors() {
|
|
10
|
+
const builtins = [
|
|
11
|
+
new GitHubConnector(),
|
|
12
|
+
new GitLabConnector(),
|
|
13
|
+
new AWSIAMConnector(),
|
|
14
|
+
new AWSS3Connector(),
|
|
15
|
+
new AWSCloudTrailConnector(),
|
|
16
|
+
new AzureADConnector(),
|
|
17
|
+
new AzureSentinelConnector(),
|
|
18
|
+
new GCPIAMConnector(),
|
|
19
|
+
new GCPSCCConnector(),
|
|
20
|
+
new OktaConnector(),
|
|
21
|
+
new JiraConnector(),
|
|
22
|
+
new SlackConnector(),
|
|
23
|
+
new PagerDutyConnector(),
|
|
24
|
+
new SnowflakeConnector(),
|
|
25
|
+
new DatadogConnector(),
|
|
26
|
+
new CrowdStrikeConnector(),
|
|
27
|
+
new QualysConnector(),
|
|
28
|
+
new SnykConnector(),
|
|
29
|
+
new TerraformCloudConnector(),
|
|
30
|
+
new GitHubActionsConnector(),
|
|
31
|
+
new DockerHubConnector(),
|
|
32
|
+
new KubernetesConnector(),
|
|
33
|
+
new SalesforceConnector(),
|
|
34
|
+
new HubSpotConnector(),
|
|
35
|
+
new BambooHRConnector(),
|
|
36
|
+
];
|
|
37
|
+
for (const connector of builtins) {
|
|
38
|
+
this.registrations.set(connector.id, {
|
|
39
|
+
connector,
|
|
40
|
+
enabled: true,
|
|
41
|
+
errorCount: 0,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
registerConnector(connector) {
|
|
46
|
+
this.registrations.set(connector.id, {
|
|
47
|
+
connector,
|
|
48
|
+
enabled: true,
|
|
49
|
+
errorCount: 0,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
unregisterConnector(connectorId) {
|
|
53
|
+
return this.registrations.delete(connectorId);
|
|
54
|
+
}
|
|
55
|
+
enableConnector(connectorId) {
|
|
56
|
+
const reg = this.registrations.get(connectorId);
|
|
57
|
+
if (reg)
|
|
58
|
+
reg.enabled = true;
|
|
59
|
+
}
|
|
60
|
+
disableConnector(connectorId) {
|
|
61
|
+
const reg = this.registrations.get(connectorId);
|
|
62
|
+
if (reg)
|
|
63
|
+
reg.enabled = false;
|
|
64
|
+
}
|
|
65
|
+
setConfig(connectorId, config) {
|
|
66
|
+
this.configs.set(connectorId, config);
|
|
67
|
+
}
|
|
68
|
+
getConnector(connectorId) {
|
|
69
|
+
return this.registrations.get(connectorId)?.connector;
|
|
70
|
+
}
|
|
71
|
+
getEnabledConnectors() {
|
|
72
|
+
return Array.from(this.registrations.values())
|
|
73
|
+
.filter((r) => r.enabled)
|
|
74
|
+
.map((r) => r.connector);
|
|
75
|
+
}
|
|
76
|
+
getConnectorsByCategory(category) {
|
|
77
|
+
return this.getEnabledConnectors().filter((c) => c.category === category);
|
|
78
|
+
}
|
|
79
|
+
getConnectorsByFramework(framework) {
|
|
80
|
+
return this.getEnabledConnectors().filter((c) => c.frameworks.includes(framework));
|
|
81
|
+
}
|
|
82
|
+
async testAllConnections() {
|
|
83
|
+
const results = new Map();
|
|
84
|
+
for (const [id, reg] of this.registrations) {
|
|
85
|
+
if (reg.enabled) {
|
|
86
|
+
const config = this.configs.get(id);
|
|
87
|
+
if (config) {
|
|
88
|
+
try {
|
|
89
|
+
results.set(id, await reg.connector.testConnection(config));
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
results.set(id, false);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
results.set(id, false);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return results;
|
|
101
|
+
}
|
|
102
|
+
async collectFromConnector(connectorId) {
|
|
103
|
+
const reg = this.registrations.get(connectorId);
|
|
104
|
+
if (!reg)
|
|
105
|
+
throw new Error(`Connector not found: ${connectorId}`);
|
|
106
|
+
const config = this.configs.get(connectorId);
|
|
107
|
+
if (!config)
|
|
108
|
+
throw new Error(`No config for connector: ${connectorId}`);
|
|
109
|
+
const job = {
|
|
110
|
+
id: `job-${Date.now()}-${connectorId}`,
|
|
111
|
+
connectorId,
|
|
112
|
+
startedAt: new Date().toISOString(),
|
|
113
|
+
status: "running",
|
|
114
|
+
artifacts: [],
|
|
115
|
+
};
|
|
116
|
+
this.jobs.push(job);
|
|
117
|
+
try {
|
|
118
|
+
job.artifacts = await reg.connector.collectEvidence(config);
|
|
119
|
+
job.status = "completed";
|
|
120
|
+
job.completedAt = new Date().toISOString();
|
|
121
|
+
reg.lastCollectedAt = job.completedAt;
|
|
122
|
+
reg.errorCount = 0;
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
job.status = "failed";
|
|
126
|
+
job.completedAt = new Date().toISOString();
|
|
127
|
+
job.error = err instanceof Error ? err.message : String(err);
|
|
128
|
+
reg.errorCount++;
|
|
129
|
+
}
|
|
130
|
+
return job;
|
|
131
|
+
}
|
|
132
|
+
async collectAll() {
|
|
133
|
+
const jobs = [];
|
|
134
|
+
for (const reg of this.registrations.values()) {
|
|
135
|
+
if (reg.enabled && this.configs.has(reg.connector.id)) {
|
|
136
|
+
jobs.push(await this.collectFromConnector(reg.connector.id));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return jobs;
|
|
140
|
+
}
|
|
141
|
+
getStats() {
|
|
142
|
+
const connectors = this.getEnabledConnectors();
|
|
143
|
+
const byCategory = {};
|
|
144
|
+
const allFrameworks = new Set();
|
|
145
|
+
let totalCapabilities = 0;
|
|
146
|
+
for (const c of connectors) {
|
|
147
|
+
byCategory[c.category] = (byCategory[c.category] || 0) + 1;
|
|
148
|
+
totalCapabilities += c.capabilities.length;
|
|
149
|
+
for (const f of c.frameworks)
|
|
150
|
+
allFrameworks.add(f);
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
totalConnectors: connectors.length,
|
|
154
|
+
connectorsByCategory: byCategory,
|
|
155
|
+
totalCapabilities,
|
|
156
|
+
frameworksSupported: Array.from(allFrameworks),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
getJobs() {
|
|
160
|
+
return [...this.jobs];
|
|
161
|
+
}
|
|
162
|
+
getRecentJobs(limit = 10) {
|
|
163
|
+
return this.jobs.slice(-limit);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { IntegrationConnector, ConnectorConfig, EvidenceArtifact, IntegrationCapability, ComplianceFramework } from "../types.js";
|
|
2
|
+
export declare class AWSCloudTrailConnector implements IntegrationConnector {
|
|
3
|
+
readonly id = "aws-cloudtrail";
|
|
4
|
+
readonly name = "AWS CloudTrail";
|
|
5
|
+
readonly category: "cloud_provider";
|
|
6
|
+
readonly authType: "service_account";
|
|
7
|
+
readonly capabilities: IntegrationCapability[];
|
|
8
|
+
readonly frameworks: ComplianceFramework[];
|
|
9
|
+
private fetchCloudTrail;
|
|
10
|
+
testConnection(config: ConnectorConfig): Promise<boolean>;
|
|
11
|
+
collectEvidence(config: ConnectorConfig): Promise<EvidenceArtifact[]>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { hashEvidence, generateEvidenceId } from "../types.js";
|
|
2
|
+
const capabilities = [
|
|
3
|
+
{
|
|
4
|
+
id: "ct-audit-logs",
|
|
5
|
+
name: "CloudTrail Audit Logs",
|
|
6
|
+
description: "Fetch CloudTrail event history and trail configuration",
|
|
7
|
+
evidenceCategories: ["logging", "audit"],
|
|
8
|
+
},
|
|
9
|
+
];
|
|
10
|
+
export class AWSCloudTrailConnector {
|
|
11
|
+
id = "aws-cloudtrail";
|
|
12
|
+
name = "AWS CloudTrail";
|
|
13
|
+
category = "cloud_provider";
|
|
14
|
+
authType = "service_account";
|
|
15
|
+
capabilities = capabilities;
|
|
16
|
+
frameworks = [
|
|
17
|
+
"SOC2",
|
|
18
|
+
"ISO27001",
|
|
19
|
+
"NIST_CSF",
|
|
20
|
+
"HIPAA",
|
|
21
|
+
"PCI_DSS",
|
|
22
|
+
];
|
|
23
|
+
async fetchCloudTrail(config, action, params = {}) {
|
|
24
|
+
const region = config.region || "us-east-1";
|
|
25
|
+
const host = `cloudtrail.${region}.amazonaws.com`;
|
|
26
|
+
const query = new URLSearchParams({ Action: action, Version: "2013-11-01", ...params });
|
|
27
|
+
const resp = await fetch(`https://${host}/?${query}`, {
|
|
28
|
+
headers: {
|
|
29
|
+
Authorization: `AWS4-HMAC-SHA256 Credential=${config.apiToken}/${region}/cloudtrail/aws4_request`,
|
|
30
|
+
"X-Amz-Date": new Date().toISOString().replace(/[:-]|\.\d{3}/g, ""),
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
if (!resp.ok)
|
|
34
|
+
throw new Error(`CloudTrail ${resp.status}`);
|
|
35
|
+
return (await resp.json());
|
|
36
|
+
}
|
|
37
|
+
async testConnection(config) {
|
|
38
|
+
try {
|
|
39
|
+
await this.fetchCloudTrail(config, "DescribeTrails");
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async collectEvidence(config) {
|
|
47
|
+
const now = new Date().toISOString();
|
|
48
|
+
const trails = await this.fetchCloudTrail(config, "DescribeTrails").catch(() => ({
|
|
49
|
+
trailList: [],
|
|
50
|
+
}));
|
|
51
|
+
const trailList = (trails.trailList || []);
|
|
52
|
+
return [
|
|
53
|
+
{
|
|
54
|
+
id: generateEvidenceId(),
|
|
55
|
+
connectorId: this.id,
|
|
56
|
+
capabilityId: "ct-audit-logs",
|
|
57
|
+
timestamp: now,
|
|
58
|
+
hash: hashEvidence(trails),
|
|
59
|
+
framework: "SOC2",
|
|
60
|
+
controlId: "CC7.1",
|
|
61
|
+
source: "aws-cloudtrail/DescribeTrails",
|
|
62
|
+
status: trailList.length > 0 ? "compliant" : "non_compliant",
|
|
63
|
+
data: {
|
|
64
|
+
trailCount: trailList.length,
|
|
65
|
+
trails: trailList.map((t) => ({
|
|
66
|
+
name: t.Name,
|
|
67
|
+
s3BucketName: t.S3BucketName,
|
|
68
|
+
isMultiRegionTrail: t.IsMultiRegionTrail,
|
|
69
|
+
isOrganizationTrail: t.IsOrganizationTrail,
|
|
70
|
+
logFileValidationEnabled: t.LogFileValidationEnabled,
|
|
71
|
+
})),
|
|
72
|
+
},
|
|
73
|
+
metadata: { region: config.region || "us-east-1" },
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { IntegrationConnector, ConnectorConfig, EvidenceArtifact, IntegrationCapability, ComplianceFramework } from "../types.js";
|
|
2
|
+
export declare class AWSIAMConnector implements IntegrationConnector {
|
|
3
|
+
readonly id = "aws-iam";
|
|
4
|
+
readonly name = "AWS IAM";
|
|
5
|
+
readonly category: "cloud_provider";
|
|
6
|
+
readonly authType: "service_account";
|
|
7
|
+
readonly capabilities: IntegrationCapability[];
|
|
8
|
+
readonly frameworks: ComplianceFramework[];
|
|
9
|
+
private fetchAws;
|
|
10
|
+
testConnection(config: ConnectorConfig): Promise<boolean>;
|
|
11
|
+
collectEvidence(config: ConnectorConfig): Promise<EvidenceArtifact[]>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { hashEvidence, generateEvidenceId } from "../types.js";
|
|
2
|
+
const capabilities = [
|
|
3
|
+
{
|
|
4
|
+
id: "aws-iam-policies",
|
|
5
|
+
name: "IAM Policies",
|
|
6
|
+
description: "Fetch IAM policies, attached managed policies, and inline policies",
|
|
7
|
+
evidenceCategories: ["access_control"],
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
id: "aws-iam-access-analyzer",
|
|
11
|
+
name: "IAM Access Analyzer",
|
|
12
|
+
description: "Fetch Access Analyzer findings for cross-account and external access",
|
|
13
|
+
evidenceCategories: ["access_control", "risk_management"],
|
|
14
|
+
},
|
|
15
|
+
];
|
|
16
|
+
export class AWSIAMConnector {
|
|
17
|
+
id = "aws-iam";
|
|
18
|
+
name = "AWS IAM";
|
|
19
|
+
category = "cloud_provider";
|
|
20
|
+
authType = "service_account";
|
|
21
|
+
capabilities = capabilities;
|
|
22
|
+
frameworks = [
|
|
23
|
+
"SOC2",
|
|
24
|
+
"ISO27001",
|
|
25
|
+
"NIST_CSF",
|
|
26
|
+
"HIPAA",
|
|
27
|
+
"PCI_DSS",
|
|
28
|
+
];
|
|
29
|
+
async fetchAws(config, service, action, params = {}) {
|
|
30
|
+
const region = config.region || "us-east-1";
|
|
31
|
+
const host = `${service}.${region}.amazonaws.com`;
|
|
32
|
+
const query = new URLSearchParams({ Action: action, Version: "2010-05-08", ...params });
|
|
33
|
+
const resp = await fetch(`https://${host}/?${query}`, {
|
|
34
|
+
headers: {
|
|
35
|
+
Authorization: `AWS4-HMAC-SHA256 Credential=${config.apiToken}/${region}/${service}/aws4_request`,
|
|
36
|
+
"X-Amz-Date": new Date().toISOString().replace(/[:-]|\.\d{3}/g, ""),
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
if (!resp.ok)
|
|
40
|
+
throw new Error(`AWS ${service} ${resp.status}: ${resp.statusText}`);
|
|
41
|
+
const text = await resp.text();
|
|
42
|
+
return { raw: text };
|
|
43
|
+
}
|
|
44
|
+
async testConnection(config) {
|
|
45
|
+
try {
|
|
46
|
+
await this.fetchAws(config, "iam", "GetCallerIdentity");
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async collectEvidence(config) {
|
|
54
|
+
const artifacts = [];
|
|
55
|
+
const now = new Date().toISOString();
|
|
56
|
+
const policies = await this.fetchAws(config, "iam", "ListPolicies", {
|
|
57
|
+
Scope: "Local",
|
|
58
|
+
}).catch(() => ({ policies: [] }));
|
|
59
|
+
artifacts.push({
|
|
60
|
+
id: generateEvidenceId(),
|
|
61
|
+
connectorId: this.id,
|
|
62
|
+
capabilityId: "aws-iam-policies",
|
|
63
|
+
timestamp: now,
|
|
64
|
+
hash: hashEvidence(policies),
|
|
65
|
+
framework: "SOC2",
|
|
66
|
+
controlId: "CC6.1",
|
|
67
|
+
source: "aws-iam/ListPolicies",
|
|
68
|
+
status: "unknown",
|
|
69
|
+
data: { policies },
|
|
70
|
+
metadata: { region: config.region || "us-east-1" },
|
|
71
|
+
});
|
|
72
|
+
const analyzer = await this.fetchAws(config, "accessanalyzer", "ListFindings", {
|
|
73
|
+
analyzerArn: config.extra?.analyzerArn || "",
|
|
74
|
+
}).catch(() => ({ findings: [] }));
|
|
75
|
+
artifacts.push({
|
|
76
|
+
id: generateEvidenceId(),
|
|
77
|
+
connectorId: this.id,
|
|
78
|
+
capabilityId: "aws-iam-access-analyzer",
|
|
79
|
+
timestamp: now,
|
|
80
|
+
hash: hashEvidence(analyzer),
|
|
81
|
+
framework: "SOC2",
|
|
82
|
+
controlId: "CC6.2",
|
|
83
|
+
source: "aws-access-analyzer/ListFindings",
|
|
84
|
+
status: "unknown",
|
|
85
|
+
data: { findings: analyzer },
|
|
86
|
+
metadata: { region: config.region || "us-east-1" },
|
|
87
|
+
});
|
|
88
|
+
return artifacts;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { IntegrationConnector, ConnectorConfig, EvidenceArtifact, IntegrationCapability, ComplianceFramework } from "../types.js";
|
|
2
|
+
export declare class AWSS3Connector implements IntegrationConnector {
|
|
3
|
+
readonly id = "aws-s3";
|
|
4
|
+
readonly name = "AWS S3";
|
|
5
|
+
readonly category: "cloud_provider";
|
|
6
|
+
readonly authType: "service_account";
|
|
7
|
+
readonly capabilities: IntegrationCapability[];
|
|
8
|
+
readonly frameworks: ComplianceFramework[];
|
|
9
|
+
private fetchS3;
|
|
10
|
+
testConnection(config: ConnectorConfig): Promise<boolean>;
|
|
11
|
+
collectEvidence(config: ConnectorConfig): Promise<EvidenceArtifact[]>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { hashEvidence, generateEvidenceId } from "../types.js";
|
|
2
|
+
const capabilities = [
|
|
3
|
+
{
|
|
4
|
+
id: "s3-encryption",
|
|
5
|
+
name: "Bucket Encryption",
|
|
6
|
+
description: "Fetch S3 bucket default encryption configuration",
|
|
7
|
+
evidenceCategories: ["encryption"],
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
id: "s3-versioning",
|
|
11
|
+
name: "Bucket Versioning",
|
|
12
|
+
description: "Fetch S3 bucket versioning status",
|
|
13
|
+
evidenceCategories: ["data_protection"],
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
id: "s3-logging",
|
|
17
|
+
name: "Bucket Access Logging",
|
|
18
|
+
description: "Fetch S3 bucket server access logging configuration",
|
|
19
|
+
evidenceCategories: ["logging"],
|
|
20
|
+
},
|
|
21
|
+
];
|
|
22
|
+
export class AWSS3Connector {
|
|
23
|
+
id = "aws-s3";
|
|
24
|
+
name = "AWS S3";
|
|
25
|
+
category = "cloud_provider";
|
|
26
|
+
authType = "service_account";
|
|
27
|
+
capabilities = capabilities;
|
|
28
|
+
frameworks = [
|
|
29
|
+
"SOC2",
|
|
30
|
+
"ISO27001",
|
|
31
|
+
"NIST_CSF",
|
|
32
|
+
"HIPAA",
|
|
33
|
+
"PCI_DSS",
|
|
34
|
+
];
|
|
35
|
+
async fetchS3(config, bucket, action) {
|
|
36
|
+
const region = config.region || "us-east-1";
|
|
37
|
+
const resp = await fetch(`https://${bucket}.s3.${region}.amazonaws.com/?${action}`, {
|
|
38
|
+
headers: {
|
|
39
|
+
Authorization: `AWS4-HMAC-SHA256 Credential=${config.apiToken}/${region}/s3/aws4_request`,
|
|
40
|
+
"X-Amz-Date": new Date().toISOString().replace(/[:-]|\.\d{3}/g, ""),
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
if (!resp.ok)
|
|
44
|
+
throw new Error(`S3 ${action} failed: ${resp.status}`);
|
|
45
|
+
const text = await resp.text();
|
|
46
|
+
return { raw: text };
|
|
47
|
+
}
|
|
48
|
+
async testConnection(config) {
|
|
49
|
+
try {
|
|
50
|
+
const bucket = config.extra?.bucket || "test-bucket";
|
|
51
|
+
await this.fetchS3(config, bucket, "list-type=2&max-keys=1");
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async collectEvidence(config) {
|
|
59
|
+
const artifacts = [];
|
|
60
|
+
const now = new Date().toISOString();
|
|
61
|
+
const bucket = config.extra?.bucket || "main-bucket";
|
|
62
|
+
const encryption = await this.fetchS3(config, bucket, "encryption").catch(() => ({
|
|
63
|
+
enabled: false,
|
|
64
|
+
}));
|
|
65
|
+
artifacts.push({
|
|
66
|
+
id: generateEvidenceId(),
|
|
67
|
+
connectorId: this.id,
|
|
68
|
+
capabilityId: "s3-encryption",
|
|
69
|
+
timestamp: now,
|
|
70
|
+
hash: hashEvidence(encryption),
|
|
71
|
+
framework: "SOC2",
|
|
72
|
+
controlId: "CC6.1",
|
|
73
|
+
source: `s3://${bucket}/encryption`,
|
|
74
|
+
status: encryption.enabled !== false ? "compliant" : "non_compliant",
|
|
75
|
+
data: { bucket, encryption },
|
|
76
|
+
metadata: { region: config.region || "us-east-1" },
|
|
77
|
+
});
|
|
78
|
+
const versioning = await this.fetchS3(config, bucket, "versioning").catch(() => ({
|
|
79
|
+
status: "Suspended",
|
|
80
|
+
}));
|
|
81
|
+
artifacts.push({
|
|
82
|
+
id: generateEvidenceId(),
|
|
83
|
+
connectorId: this.id,
|
|
84
|
+
capabilityId: "s3-versioning",
|
|
85
|
+
timestamp: now,
|
|
86
|
+
hash: hashEvidence(versioning),
|
|
87
|
+
framework: "ISO27001",
|
|
88
|
+
controlId: "A.12.3.1",
|
|
89
|
+
source: `s3://${bucket}/versioning`,
|
|
90
|
+
status: versioning.status === "Enabled" ? "compliant" : "non_compliant",
|
|
91
|
+
data: { bucket, versioning },
|
|
92
|
+
metadata: { region: config.region || "us-east-1" },
|
|
93
|
+
});
|
|
94
|
+
const logging = await this.fetchS3(config, bucket, "logging").catch(() => ({
|
|
95
|
+
enabled: false,
|
|
96
|
+
}));
|
|
97
|
+
artifacts.push({
|
|
98
|
+
id: generateEvidenceId(),
|
|
99
|
+
connectorId: this.id,
|
|
100
|
+
capabilityId: "s3-logging",
|
|
101
|
+
timestamp: now,
|
|
102
|
+
hash: hashEvidence(logging),
|
|
103
|
+
framework: "SOC2",
|
|
104
|
+
controlId: "CC7.1",
|
|
105
|
+
source: `s3://${bucket}/logging`,
|
|
106
|
+
status: logging.enabled !== false ? "compliant" : "non_compliant",
|
|
107
|
+
data: { bucket, logging },
|
|
108
|
+
metadata: { region: config.region || "us-east-1" },
|
|
109
|
+
});
|
|
110
|
+
return artifacts;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { IntegrationConnector, ConnectorConfig, EvidenceArtifact, IntegrationCapability, ComplianceFramework } from "../types.js";
|
|
2
|
+
export declare class AzureADConnector implements IntegrationConnector {
|
|
3
|
+
readonly id = "azure-ad";
|
|
4
|
+
readonly name = "Azure Active Directory";
|
|
5
|
+
readonly category: "identity";
|
|
6
|
+
readonly authType: "oauth2";
|
|
7
|
+
readonly capabilities: IntegrationCapability[];
|
|
8
|
+
readonly frameworks: ComplianceFramework[];
|
|
9
|
+
private getAccessToken;
|
|
10
|
+
testConnection(config: ConnectorConfig): Promise<boolean>;
|
|
11
|
+
collectEvidence(config: ConnectorConfig): Promise<EvidenceArtifact[]>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { hashEvidence, generateEvidenceId } from "../types.js";
|
|
2
|
+
const capabilities = [
|
|
3
|
+
{
|
|
4
|
+
id: "aad-conditional-access",
|
|
5
|
+
name: "Conditional Access Policies",
|
|
6
|
+
description: "Fetch Azure AD conditional access policies",
|
|
7
|
+
evidenceCategories: ["access_control"],
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
id: "aad-mfa-enrollment",
|
|
11
|
+
name: "MFA Enrollment",
|
|
12
|
+
description: "Fetch MFA enrollment statistics and per-user MFA status",
|
|
13
|
+
evidenceCategories: ["authentication"],
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
id: "aad-app-registrations",
|
|
17
|
+
name: "App Registrations",
|
|
18
|
+
description: "Fetch app registrations and service principals",
|
|
19
|
+
evidenceCategories: ["access_control", "application_security"],
|
|
20
|
+
},
|
|
21
|
+
];
|
|
22
|
+
export class AzureADConnector {
|
|
23
|
+
id = "azure-ad";
|
|
24
|
+
name = "Azure Active Directory";
|
|
25
|
+
category = "identity";
|
|
26
|
+
authType = "oauth2";
|
|
27
|
+
capabilities = capabilities;
|
|
28
|
+
frameworks = [
|
|
29
|
+
"SOC2",
|
|
30
|
+
"ISO27001",
|
|
31
|
+
"NIST_CSF",
|
|
32
|
+
"HIPAA",
|
|
33
|
+
];
|
|
34
|
+
async getAccessToken(config) {
|
|
35
|
+
const resp = await fetch(`https://login.microsoftonline.com/${config.tenantId}/oauth2/v2.0/token`, {
|
|
36
|
+
method: "POST",
|
|
37
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
38
|
+
body: new URLSearchParams({
|
|
39
|
+
grant_type: "client_credentials",
|
|
40
|
+
client_id: config.clientId || "",
|
|
41
|
+
client_secret: config.clientSecret || "",
|
|
42
|
+
scope: "https://graph.microsoft.com/.default",
|
|
43
|
+
}),
|
|
44
|
+
});
|
|
45
|
+
if (!resp.ok)
|
|
46
|
+
throw new Error(`Azure AD token ${resp.status}`);
|
|
47
|
+
const data = (await resp.json());
|
|
48
|
+
return data.access_token;
|
|
49
|
+
}
|
|
50
|
+
async testConnection(config) {
|
|
51
|
+
try {
|
|
52
|
+
const token = await this.getAccessToken(config);
|
|
53
|
+
const resp = await fetch("https://graph.microsoft.com/v1.0/$metadata", {
|
|
54
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
55
|
+
});
|
|
56
|
+
return resp.ok;
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async collectEvidence(config) {
|
|
63
|
+
const artifacts = [];
|
|
64
|
+
const now = new Date().toISOString();
|
|
65
|
+
const token = await this.getAccessToken(config);
|
|
66
|
+
const headers = { Authorization: `Bearer ${token}` };
|
|
67
|
+
const policies = await fetch("https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies", { headers }).then((r) => r.json());
|
|
68
|
+
artifacts.push({
|
|
69
|
+
id: generateEvidenceId(),
|
|
70
|
+
connectorId: this.id,
|
|
71
|
+
capabilityId: "aad-conditional-access",
|
|
72
|
+
timestamp: now,
|
|
73
|
+
hash: hashEvidence(policies),
|
|
74
|
+
framework: "SOC2",
|
|
75
|
+
controlId: "CC6.1",
|
|
76
|
+
source: "azure-ad/conditionalAccess/policies",
|
|
77
|
+
status: (policies.value || []).length > 0 ? "compliant" : "non_compliant",
|
|
78
|
+
data: { policyCount: (policies.value || []).length, policies: policies.value },
|
|
79
|
+
metadata: { tenantId: config.tenantId || "" },
|
|
80
|
+
});
|
|
81
|
+
const mfaReport = await fetch("https://graph.microsoft.com/v1.0/reports/authenticationMethods/userRegistrationDetails?$select=isMfaRegistered,isMfaCapable", { headers }).then((r) => r.json());
|
|
82
|
+
const users = (mfaReport.value || []);
|
|
83
|
+
const mfaRegistered = users.filter((u) => u.isMfaRegistered === true).length;
|
|
84
|
+
artifacts.push({
|
|
85
|
+
id: generateEvidenceId(),
|
|
86
|
+
connectorId: this.id,
|
|
87
|
+
capabilityId: "aad-mfa-enrollment",
|
|
88
|
+
timestamp: now,
|
|
89
|
+
hash: hashEvidence(mfaReport),
|
|
90
|
+
framework: "SOC2",
|
|
91
|
+
controlId: "CC6.1",
|
|
92
|
+
source: "azure-ad/authenticationMethods/userRegistrationDetails",
|
|
93
|
+
status: users.length > 0 && mfaRegistered / users.length > 0.9 ? "compliant" : "partial",
|
|
94
|
+
data: { totalUsers: users.length, mfaRegistered, mfaCapable: users.filter((u) => u.isMfaCapable === true).length },
|
|
95
|
+
metadata: { tenantId: config.tenantId || "" },
|
|
96
|
+
});
|
|
97
|
+
const apps = await fetch("https://graph.microsoft.com/v1.0/applicationRegistrations", {
|
|
98
|
+
headers,
|
|
99
|
+
}).then((r) => r.json());
|
|
100
|
+
artifacts.push({
|
|
101
|
+
id: generateEvidenceId(),
|
|
102
|
+
connectorId: this.id,
|
|
103
|
+
capabilityId: "aad-app-registrations",
|
|
104
|
+
timestamp: now,
|
|
105
|
+
hash: hashEvidence(apps),
|
|
106
|
+
framework: "ISO27001",
|
|
107
|
+
controlId: "A.14.2.5",
|
|
108
|
+
source: "azure-ad/applicationRegistrations",
|
|
109
|
+
status: "unknown",
|
|
110
|
+
data: { appCount: (apps.value || []).length, apps: apps.value },
|
|
111
|
+
metadata: { tenantId: config.tenantId || "" },
|
|
112
|
+
});
|
|
113
|
+
return artifacts;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { IntegrationConnector, ConnectorConfig, EvidenceArtifact, IntegrationCapability, ComplianceFramework } from "../types.js";
|
|
2
|
+
export declare class AzureSentinelConnector implements IntegrationConnector {
|
|
3
|
+
readonly id = "azure-sentinel";
|
|
4
|
+
readonly name = "Microsoft Sentinel";
|
|
5
|
+
readonly category: "siem";
|
|
6
|
+
readonly authType: "oauth2";
|
|
7
|
+
readonly capabilities: IntegrationCapability[];
|
|
8
|
+
readonly frameworks: ComplianceFramework[];
|
|
9
|
+
private getAccessToken;
|
|
10
|
+
testConnection(config: ConnectorConfig): Promise<boolean>;
|
|
11
|
+
collectEvidence(config: ConnectorConfig): Promise<EvidenceArtifact[]>;
|
|
12
|
+
}
|