@runsec/mcp 1.0.76 → 1.0.77
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/index.js +79 -18
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5775,6 +5775,45 @@ function isRemediationTool(name) {
|
|
|
5775
5775
|
return REMEDIATION_TOOL_NAMES.includes(name);
|
|
5776
5776
|
}
|
|
5777
5777
|
|
|
5778
|
+
// src/hubUploadUrl.ts
|
|
5779
|
+
var HUB_UPLOAD_REPORT_PATH = "/api/mcp/upload-report";
|
|
5780
|
+
var LEGACY_TELEMETRY_INGEST_PATH = "/api/v1/telemetry/ingest";
|
|
5781
|
+
function stripTrailingSlash(url) {
|
|
5782
|
+
return url.replace(/\/$/, "");
|
|
5783
|
+
}
|
|
5784
|
+
function migrateLegacyIngestUrl(url) {
|
|
5785
|
+
if (!url.includes(LEGACY_TELEMETRY_INGEST_PATH)) return url;
|
|
5786
|
+
console.warn(
|
|
5787
|
+
`[runsec] Legacy telemetry ingest URL detected (${LEGACY_TELEMETRY_INGEST_PATH}); using ${HUB_UPLOAD_REPORT_PATH} instead`
|
|
5788
|
+
);
|
|
5789
|
+
return url.replace(LEGACY_TELEMETRY_INGEST_PATH, HUB_UPLOAD_REPORT_PATH);
|
|
5790
|
+
}
|
|
5791
|
+
function resolveHubUploadUrl() {
|
|
5792
|
+
const explicit = [
|
|
5793
|
+
process.env.RUNSEC_HUB_INGEST_URL,
|
|
5794
|
+
process.env.RUNSEC_HUB_UPLOAD_URL,
|
|
5795
|
+
process.env.RUNSEC_TELEMETRY_URL
|
|
5796
|
+
].map((v) => v?.trim()).find(Boolean);
|
|
5797
|
+
if (explicit) {
|
|
5798
|
+
const migrated = migrateLegacyIngestUrl(explicit);
|
|
5799
|
+
if (migrated.includes(HUB_UPLOAD_REPORT_PATH)) {
|
|
5800
|
+
return stripTrailingSlash(migrated);
|
|
5801
|
+
}
|
|
5802
|
+
if (/^https?:\/\//i.test(migrated)) {
|
|
5803
|
+
return `${stripTrailingSlash(migrated)}${HUB_UPLOAD_REPORT_PATH}`;
|
|
5804
|
+
}
|
|
5805
|
+
return stripTrailingSlash(migrated);
|
|
5806
|
+
}
|
|
5807
|
+
const base = stripTrailingSlash(
|
|
5808
|
+
process.env.RUNSEC_HUB_URL?.trim() || process.env.RUNSEC_API_URL?.trim() || "https://runsec.io"
|
|
5809
|
+
);
|
|
5810
|
+
const migratedBase = migrateLegacyIngestUrl(base);
|
|
5811
|
+
if (migratedBase.includes(HUB_UPLOAD_REPORT_PATH)) {
|
|
5812
|
+
return migratedBase;
|
|
5813
|
+
}
|
|
5814
|
+
return `${migratedBase}${HUB_UPLOAD_REPORT_PATH}`;
|
|
5815
|
+
}
|
|
5816
|
+
|
|
5778
5817
|
// src/complianceScores.ts
|
|
5779
5818
|
var SEVERITY_PENALTY = {
|
|
5780
5819
|
CRITICAL: 15,
|
|
@@ -5817,6 +5856,26 @@ function buildHubComplianceBlock(result) {
|
|
|
5817
5856
|
}
|
|
5818
5857
|
|
|
5819
5858
|
// src/telemetryClient.ts
|
|
5859
|
+
var HUB_UPLOAD_TIMEOUT_MS = 12e4;
|
|
5860
|
+
function hubAuthHeaders(apiKey) {
|
|
5861
|
+
return {
|
|
5862
|
+
Authorization: `Bearer ${apiKey}`,
|
|
5863
|
+
// Cloudflare/tunnel may strip Authorization on POST; Hub accepts this duplicate.
|
|
5864
|
+
"X-RunSec-Api-Key": apiKey,
|
|
5865
|
+
"Content-Type": "application/json",
|
|
5866
|
+
Accept: "application/json"
|
|
5867
|
+
};
|
|
5868
|
+
}
|
|
5869
|
+
function formatHubSyncErrorMessage(error, targetUrl, response) {
|
|
5870
|
+
const status = response?.status != null ? String(response.status) : error?.response?.status != null ? String(error.response.status) : "n/a";
|
|
5871
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
5872
|
+
const cause = err.cause instanceof Error ? err.cause.message : err.cause != null ? String(err.cause) : "";
|
|
5873
|
+
let message = `Sync failed: ${err.message}. Target URL: ${targetUrl}. Status: ${status}`;
|
|
5874
|
+
if (cause && !message.includes(cause)) {
|
|
5875
|
+
message += `. Cause: ${cause}`;
|
|
5876
|
+
}
|
|
5877
|
+
return message;
|
|
5878
|
+
}
|
|
5820
5879
|
function countSeverityMetrics(findings) {
|
|
5821
5880
|
const metrics = { critical: 0, high: 0, medium: 0, low: 0, total: 0 };
|
|
5822
5881
|
for (const f of findings) {
|
|
@@ -5872,30 +5931,29 @@ async function uploadScanResultsToHub(payload, apiKey) {
|
|
|
5872
5931
|
console.warn("[runsec] Hub telemetry skipped: API key missing");
|
|
5873
5932
|
return { success: false, message: "Sync failed: API key missing" };
|
|
5874
5933
|
}
|
|
5875
|
-
const
|
|
5876
|
-
|
|
5934
|
+
const url = resolveHubUploadUrl();
|
|
5935
|
+
console.error(`[runsec] Hub telemetry upload \u2192 ${url}`);
|
|
5877
5936
|
try {
|
|
5878
5937
|
const response = await fetch(url, {
|
|
5879
5938
|
method: "POST",
|
|
5880
|
-
headers:
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
"X-RunSec-Api-Key": trimmedKey,
|
|
5884
|
-
"Content-Type": "application/json",
|
|
5885
|
-
Accept: "application/json"
|
|
5886
|
-
},
|
|
5887
|
-
body: JSON.stringify(payload)
|
|
5939
|
+
headers: hubAuthHeaders(trimmedKey),
|
|
5940
|
+
body: JSON.stringify(payload),
|
|
5941
|
+
signal: AbortSignal.timeout(HUB_UPLOAD_TIMEOUT_MS)
|
|
5888
5942
|
});
|
|
5889
5943
|
if (!response.ok) {
|
|
5890
5944
|
const detail = await response.text().catch(() => "");
|
|
5891
5945
|
const detailSnippet = detail.slice(0, 500).trim();
|
|
5892
5946
|
const statusLabel = response.statusText || String(response.status);
|
|
5893
|
-
|
|
5894
|
-
|
|
5947
|
+
const httpMessage = detailSnippet || statusLabel;
|
|
5948
|
+
const message = formatHubSyncErrorMessage(
|
|
5949
|
+
new Error(httpMessage),
|
|
5950
|
+
url,
|
|
5951
|
+
response
|
|
5895
5952
|
);
|
|
5953
|
+
console.warn(`[runsec] Hub telemetry upload failed: ${message}`);
|
|
5896
5954
|
return {
|
|
5897
5955
|
success: false,
|
|
5898
|
-
message
|
|
5956
|
+
message
|
|
5899
5957
|
};
|
|
5900
5958
|
}
|
|
5901
5959
|
const body = await response.json().catch(() => ({}));
|
|
@@ -5911,9 +5969,9 @@ async function uploadScanResultsToHub(payload, apiKey) {
|
|
|
5911
5969
|
projectId
|
|
5912
5970
|
};
|
|
5913
5971
|
} catch (error) {
|
|
5914
|
-
const message = error
|
|
5972
|
+
const message = formatHubSyncErrorMessage(error, url);
|
|
5915
5973
|
console.warn(`[runsec] Hub telemetry upload error (scan saved locally): ${message}`);
|
|
5916
|
-
return { success: false, message
|
|
5974
|
+
return { success: false, message };
|
|
5917
5975
|
}
|
|
5918
5976
|
}
|
|
5919
5977
|
|
|
@@ -5955,10 +6013,13 @@ function appendCloudSyncToDirective(directive, syncResult) {
|
|
|
5955
6013
|
${lines}`;
|
|
5956
6014
|
}
|
|
5957
6015
|
async function verifyApiKey(apiKey) {
|
|
5958
|
-
const
|
|
6016
|
+
const verifyUrl = resolveHubUploadUrl().replace(/\/upload-report\/?$/, "/verify-key");
|
|
5959
6017
|
try {
|
|
5960
|
-
const response = await fetch(
|
|
5961
|
-
headers: {
|
|
6018
|
+
const response = await fetch(verifyUrl, {
|
|
6019
|
+
headers: {
|
|
6020
|
+
Authorization: `Bearer ${apiKey}`,
|
|
6021
|
+
"X-RunSec-Api-Key": apiKey
|
|
6022
|
+
}
|
|
5962
6023
|
});
|
|
5963
6024
|
if (response.status === 401 || response.status === 403) {
|
|
5964
6025
|
console.error("\u274C FATAL: Invalid RunSec API Key.");
|