110 lines
4.5 KiB
JavaScript
110 lines
4.5 KiB
JavaScript
const unknownValue = "unknown";
|
|
|
|
export function normalizeIsoTimestamp(value) {
|
|
const source = String(value ?? "").trim();
|
|
if (!source) return null;
|
|
if (/^\d+$/u.test(source)) {
|
|
const seconds = Number.parseInt(source, 10);
|
|
if (Number.isSafeInteger(seconds)) {
|
|
const date = new Date(seconds * 1000);
|
|
if (Number.isFinite(date.getTime())) return date.toISOString();
|
|
}
|
|
}
|
|
const date = new Date(source);
|
|
return Number.isFinite(date.getTime()) ? date.toISOString() : null;
|
|
}
|
|
|
|
export function imageTagFromReference(imageReference) {
|
|
const source = String(imageReference ?? "").trim();
|
|
const slashIndex = source.lastIndexOf("/");
|
|
const colonIndex = source.lastIndexOf(":");
|
|
if (colonIndex <= slashIndex) return null;
|
|
return source.slice(colonIndex + 1) || null;
|
|
}
|
|
|
|
export function shortRevision(value) {
|
|
const source = String(value ?? "").trim();
|
|
return source.length >= 7 ? source.slice(0, 7) : source || unknownValue;
|
|
}
|
|
|
|
export function buildMetadataFromEnv(env = process.env, { serviceId = "hwlab-unknown", fallbackImageRepository = null } = {}) {
|
|
const commitId = firstNonEmpty(env.HWLAB_COMMIT_ID, env.HWLAB_GIT_SHA, env.GIT_COMMIT) ?? unknownValue;
|
|
const revision = firstNonEmpty(env.HWLAB_REVISION, commitId) ?? unknownValue;
|
|
const fallbackRepository = fallbackImageRepository ?? `ghcr.io/pikastech/${serviceId}`;
|
|
const imageReference = firstNonEmpty(env.HWLAB_IMAGE, `${fallbackRepository}:${shortRevision(commitId)}`) ?? unknownValue;
|
|
const imageTag = firstNonEmpty(env.HWLAB_IMAGE_TAG, imageTagFromReference(imageReference), shortRevision(commitId)) ?? unknownValue;
|
|
const buildCreatedAt = normalizeIsoTimestamp(
|
|
firstNonEmpty(env.HWLAB_BUILD_CREATED_AT, env.HWLAB_IMAGE_CREATED_AT, env.SOURCE_DATE_EPOCH, env.BUILD_DATE)
|
|
);
|
|
const buildSource = firstNonEmpty(env.HWLAB_BUILD_SOURCE, "runtime-env") ?? "runtime-env";
|
|
|
|
return {
|
|
revision,
|
|
commit: {
|
|
id: commitId,
|
|
source: buildSource
|
|
},
|
|
image: {
|
|
reference: imageReference,
|
|
tag: imageTag,
|
|
digest: firstNonEmpty(env.HWLAB_IMAGE_DIGEST, unknownValue) ?? unknownValue
|
|
},
|
|
build: {
|
|
createdAt: buildCreatedAt,
|
|
source: buildSource,
|
|
provenance: firstNonEmpty(env.HWLAB_BUILD_PROVENANCE, null),
|
|
metadataSource: buildCreatedAt ? "runtime-env:HWLAB_BUILD_CREATED_AT" : "unavailable",
|
|
unavailableReason: buildCreatedAt ? null : "HWLAB_BUILD_CREATED_AT missing from runtime environment"
|
|
},
|
|
runtime: runtimeIdentityFromEnv(env)
|
|
};
|
|
}
|
|
|
|
export function runtimeIdentityFromEnv(env = process.env) {
|
|
const runtimeMode = firstNonEmpty(env.HWLAB_RUNTIME_MODE, null);
|
|
const bootRepo = firstNonEmpty(env.HWLAB_BOOT_REPO, null);
|
|
const bootCommit = firstNonEmpty(env.HWLAB_BOOT_COMMIT, null);
|
|
const bootSh = firstNonEmpty(env.HWLAB_BOOT_SH, null);
|
|
const environmentImage = firstNonEmpty(env.HWLAB_ENVIRONMENT_IMAGE, null);
|
|
const environmentDigest = firstNonEmpty(env.HWLAB_ENVIRONMENT_DIGEST, env.HWLAB_IMAGE_DIGEST, null);
|
|
const environmentInputHash = firstNonEmpty(env.HWLAB_ENVIRONMENT_INPUT_HASH, null);
|
|
const codeInputHash = firstNonEmpty(env.HWLAB_CODE_INPUT_HASH, null);
|
|
const pod = runtimePodIdentityFromEnv(env);
|
|
if (!runtimeMode && !bootRepo && !bootCommit && !bootSh && !environmentDigest && !pod) return null;
|
|
return pruneUndefined({
|
|
mode: runtimeMode,
|
|
environmentImage,
|
|
environmentDigest,
|
|
environmentInputHash,
|
|
codeInputHash,
|
|
pod,
|
|
boot: pruneUndefined({
|
|
repo: bootRepo,
|
|
commit: bootCommit,
|
|
sh: bootSh
|
|
})
|
|
});
|
|
}
|
|
|
|
function runtimePodIdentityFromEnv(env = process.env) {
|
|
const name = firstNonEmpty(env.HWLAB_RUNTIME_POD_NAME, env.POD_NAME, env.HOSTNAME, null);
|
|
const namespace = firstNonEmpty(env.HWLAB_RUNTIME_NAMESPACE, env.POD_NAMESPACE, env.KUBERNETES_NAMESPACE, env.HWLAB_NAMESPACE, null);
|
|
const container = firstNonEmpty(env.HWLAB_RUNTIME_CONTAINER, env.HWLAB_CONTAINER_NAME, null);
|
|
const nodeName = firstNonEmpty(env.HWLAB_RUNTIME_NODE_NAME, env.NODE_NAME, null);
|
|
if (!name && !namespace && !container && !nodeName) return null;
|
|
return pruneUndefined({ name, namespace, container, nodeName });
|
|
}
|
|
|
|
function firstNonEmpty(...values) {
|
|
for (const value of values) {
|
|
if (value === null || value === undefined) continue;
|
|
const text = String(value).trim();
|
|
if (text) return text;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function pruneUndefined(value) {
|
|
return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== undefined && item !== null && item !== ""));
|
|
}
|