snowflake-sdk
Version:
Node.js driver for Snowflake
138 lines • 5.87 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DETECTION_TIMEOUT_MS = void 0;
exports.getDetectedPlatforms = getDetectedPlatforms;
const node_http_1 = __importDefault(require("node:http"));
const client_sts_1 = require("@aws-sdk/client-sts");
const AWS_METADATA_BASE_URL = 'http://169.254.169.254';
const AZURE_METADATA_BASE_URL = 'http://169.254.169.254';
const GCE_METADATA_ROOT_URL = 'http://metadata.google.internal';
const GCE_METADATA_BASE_URL = 'http://metadata.google.internal/computeMetadata/v1';
exports.DETECTION_TIMEOUT_MS = 200;
const DETECTORS = {
is_aws_lambda: isAwsLambda,
is_azure_function: isAzureFunction,
is_gce_cloud_run_service: isGceCloudRunService,
is_gce_cloud_run_job: isGceCloudRunJob,
is_github_action: isGithubAction,
is_ec2_instance: isEc2Instance,
has_aws_identity: hasAwsIdentity,
is_azure_vm: isAzureVm,
has_azure_managed_identity: hasAzureManagedIdentity,
is_gce_vm: isGceVm,
has_gcp_identity: hasGcpIdentity,
};
const DETECTION_RESULT = detectPlatforms();
function getDetectedPlatforms() {
return DETECTION_RESULT;
}
async function detectPlatforms() {
if (process.env['SNOWFLAKE_DISABLE_PLATFORM_DETECTION']?.toLowerCase() === 'true') {
return ['disabled'];
}
const abortSignal = AbortSignal.timeout(exports.DETECTION_TIMEOUT_MS);
const results = await Promise.all(Object.entries(DETECTORS).map(async ([name, detector]) => ({
name,
detected: await Promise.resolve(detector(abortSignal)).catch(() => false),
})));
return results.filter(({ detected }) => detected).map(({ name }) => name);
}
function isAwsLambda() {
return envPresent('LAMBDA_TASK_ROOT');
}
function isAzureFunction() {
return envPresent('FUNCTIONS_WORKER_RUNTIME', 'FUNCTIONS_EXTENSION_VERSION', 'AzureWebJobsStorage');
}
function isGceCloudRunService() {
return envPresent('K_SERVICE', 'K_REVISION', 'K_CONFIGURATION');
}
function isGceCloudRunJob() {
return envPresent('CLOUD_RUN_JOB', 'CLOUD_RUN_EXECUTION');
}
function isGithubAction() {
return envPresent('GITHUB_ACTIONS');
}
// Intentionally not using the available AWS SDK, as it does not support abort signals and is easy to
// misconfigure retry logic.
async function isEc2Instance(abortSignal) {
const tokenResult = await httpRequest(`${AWS_METADATA_BASE_URL}/latest/api/token`, abortSignal, { 'X-aws-ec2-metadata-token-ttl-seconds': '21600' }, 'PUT').catch(() => null);
const token = tokenResult?.ok ? tokenResult.body.trim() : null;
const result = await httpRequest(`${AWS_METADATA_BASE_URL}/latest/dynamic/instance-identity/document`, abortSignal, token ? { 'X-aws-ec2-metadata-token': token } : undefined);
if (!result.ok)
return false;
const doc = JSON.parse(result.body);
return !!doc.instanceId;
}
async function hasAwsIdentity(abortSignal) {
const client = new client_sts_1.STSClient({});
const response = await client.send(new client_sts_1.GetCallerIdentityCommand({}), {
abortSignal,
});
if (!response.Arn)
return false;
return isValidArnForWif(response.Arn);
}
async function isAzureVm(abortSignal) {
const result = await httpRequest(`${AZURE_METADATA_BASE_URL}/metadata/instance?api-version=2021-02-01`, abortSignal, { Metadata: 'true' });
return result.ok;
}
async function hasAzureManagedIdentity(abortSignal) {
if (isAzureFunction() && envPresent('IDENTITY_HEADER')) {
return true;
}
const params = new URLSearchParams({
'api-version': '2018-02-01',
resource: 'https://management.azure.com',
});
const result = await httpRequest(`${AZURE_METADATA_BASE_URL}/metadata/identity/oauth2/token?${params}`, abortSignal, { Metadata: 'true' });
return result.ok;
}
async function isGceVm(abortSignal) {
const result = await httpRequest(GCE_METADATA_ROOT_URL, abortSignal);
return result.headers['metadata-flavor'] === 'Google';
}
async function hasGcpIdentity(abortSignal) {
const result = await httpRequest(`${GCE_METADATA_BASE_URL}/instance/service-accounts/default/email`, abortSignal, { 'Metadata-Flavor': 'Google' });
return result.ok;
}
function envPresent(...envVars) {
return envVars.every((v) => {
const val = process.env[v];
return val !== undefined && val !== '';
});
}
function httpRequest(url, signal, headers, method = 'GET') {
const isBun = typeof process !== 'undefined' && !!process.versions?.bun;
return isBun
? httpRequestFetch(url, signal, headers, method)
: httpRequestNode(url, signal, headers, method);
}
async function httpRequestFetch(url, signal, headers, method) {
const res = await fetch(url, { method, headers, signal });
const body = await res.text();
const resHeaders = {};
res.headers.forEach((value, key) => {
resHeaders[key] = value;
});
return { ok: res.ok, headers: resHeaders, body };
}
function httpRequestNode(url, signal, headers, method) {
return new Promise((resolve, reject) => {
const req = node_http_1.default.request(url, { method, signal, headers }, (res) => {
let body = '';
const statusCode = res.statusCode ?? 0;
res.on('data', (chunk) => (body += chunk));
res.on('end', () => resolve({ ok: statusCode >= 200 && statusCode < 300, headers: res.headers, body }));
res.on('error', reject);
});
req.on('error', reject);
req.end();
});
}
function isValidArnForWif(arn) {
return [/^arn:[^:]+:iam::[^:]+:user\/.+$/, /^arn:[^:]+:sts::[^:]+:assumed-role\/.+$/].some((pattern) => pattern.test(arn));
}
//# sourceMappingURL=platform_detection.js.map