97 lines
3.9 KiB
JavaScript
97 lines
3.9 KiB
JavaScript
import { readFileSync } from "node:fs";
|
|
import https from "node:https";
|
|
|
|
const namespace = process.argv[2] || "";
|
|
const pipelineRun = process.argv[3] || "";
|
|
const host = process.env.KUBERNETES_SERVICE_HOST;
|
|
const port = Number(process.env.KUBERNETES_SERVICE_PORT || "443");
|
|
const token = readFileSync("/var/run/secrets/kubernetes.io/serviceaccount/token", "utf8").trim();
|
|
const ca = readFileSync("/var/run/secrets/kubernetes.io/serviceaccount/ca.crt");
|
|
|
|
function request(path) {
|
|
return new Promise((resolve) => {
|
|
const req = https.request({ host, port, path, method: "GET", ca, headers: { authorization: `Bearer ${token}` } }, (res) => {
|
|
let body = "";
|
|
res.setEncoding("utf8");
|
|
res.on("data", (chunk) => { body += chunk; });
|
|
res.on("end", () => resolve({ status: res.statusCode || 0, body }));
|
|
});
|
|
req.on("error", (error) => resolve({ status: 599, body: error?.message || String(error) }));
|
|
req.end();
|
|
});
|
|
}
|
|
|
|
function parse(text) {
|
|
try {
|
|
return text ? JSON.parse(text) : null;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function strings(value) {
|
|
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
}
|
|
|
|
const out = {
|
|
ok: false,
|
|
pipelineRun,
|
|
pods: [],
|
|
eventFound: false,
|
|
degradedReason: "plan-artifacts-log-query-skipped",
|
|
statusAuthority: "kubernetes-api-serviceaccount",
|
|
};
|
|
|
|
if (!namespace || !pipelineRun) {
|
|
process.stdout.write(JSON.stringify(out));
|
|
process.exit(0);
|
|
}
|
|
|
|
const selector = encodeURIComponent(`tekton.dev/pipelineRun=${pipelineRun}`);
|
|
const podsResult = await request(`/api/v1/namespaces/${encodeURIComponent(namespace)}/pods?labelSelector=${selector}`);
|
|
const pods = parse(podsResult.body);
|
|
const items = Array.isArray(pods?.items) ? pods.items : [];
|
|
const planPods = items.filter((pod) => {
|
|
const labels = pod?.metadata?.labels || {};
|
|
const name = pod?.metadata?.name || "";
|
|
return labels["tekton.dev/pipelineTask"] === "plan-artifacts" || labels["tekton.dev/task"] === "plan-artifacts" || /plan-artifacts/u.test(name);
|
|
});
|
|
out.pods = planPods.map((pod) => pod?.metadata?.name).filter(Boolean);
|
|
|
|
const events = [];
|
|
for (const podName of out.pods.slice(-4)) {
|
|
const log = await request(`/api/v1/namespaces/${encodeURIComponent(namespace)}/pods/${encodeURIComponent(podName)}/log?tailLines=240`);
|
|
if (log.status < 200 || log.status >= 300) continue;
|
|
for (const raw of log.body.split(/\r?\n/u)) {
|
|
const line = raw.trim();
|
|
if (!line.startsWith("{")) continue;
|
|
const event = parse(line);
|
|
if (event?.event === "g14-ci-plan") events.push(event);
|
|
}
|
|
}
|
|
|
|
const latest = events.at(-1) || null;
|
|
if (latest) {
|
|
const audit = latest.artifactProvenanceAudit && typeof latest.artifactProvenanceAudit === "object" ? latest.artifactProvenanceAudit : null;
|
|
const unsafeReuseServices = strings(audit?.unsafeReuseServices);
|
|
const provenanceRebuildServices = strings(audit?.provenanceRebuildServices);
|
|
Object.assign(out, {
|
|
ok: true,
|
|
eventFound: true,
|
|
degradedReason: null,
|
|
sourceCommitId: typeof latest.sourceCommitId === "string" ? latest.sourceCommitId : null,
|
|
affectedServices: strings(latest.affectedServices),
|
|
rolloutServices: strings(latest.rolloutServices),
|
|
buildServices: strings(latest.buildServices),
|
|
reusedServices: strings(latest.reusedServices),
|
|
buildSkippedCount: typeof latest.buildSkippedCount === "number" ? latest.buildSkippedCount : null,
|
|
artifactProvenanceAudit: audit,
|
|
summary: `build=${strings(latest.buildServices).length} reuse=${strings(latest.reusedServices).length} unsafeReuse=${unsafeReuseServices.length} provenanceRebuild=${provenanceRebuildServices.length}`,
|
|
disclosure: "parsed from plan-artifacts g14-ci-plan log event via Kubernetes pod logs",
|
|
});
|
|
} else {
|
|
out.degradedReason = podsResult.status >= 200 && podsResult.status < 300 ? "g14-ci-plan-event-not-found" : "plan-artifacts-pod-list-failed";
|
|
}
|
|
|
|
process.stdout.write(JSON.stringify(out));
|