Compare commits

...

11 Commits

Author SHA1 Message Date
dev a0f8bb8616 redesign: modern UI + Helm releases + update checker
Build & Push / build (push) Successful in 8s
2026-06-07 12:51:18 +02:00
dev 393fe985b8 fix: wss für HTTPS
Build & Push / build (push) Successful in 11s
2026-06-07 12:26:42 +02:00
dev 3196d0d442 fix: npm install statt npm ci
Build & Push / build (push) Successful in 41s
2026-06-07 12:01:39 +02:00
dev aa4098cfbf fix: lowercase registry path
Build & Push / build (push) Failing after 12s
2026-06-07 12:00:37 +02:00
dev 0658c9e810 fix: manual git clone statt actions/checkout
Build & Push / build (push) Failing after 1s
2026-06-07 11:32:23 +02:00
dev d8f2e2dbb0 fix: runner ohne container spec
Build & Push / build (push) Failing after 11s
2026-06-07 11:21:21 +02:00
dev d834c7b885 fix: use docker:git image
Build & Push / build (push) Failing after 25s
2026-06-07 11:18:56 +02:00
dev 618db93105 fix: use docker container for job
Build & Push / build (push) Failing after 24s
2026-06-07 11:16:05 +02:00
dev 840bb32a5d trigger CI
Build & Push / build (push) Failing after 1m31s
2026-06-07 11:11:55 +02:00
dev 076e9a81db trigger CI
Build & Push / build (push) Has been cancelled
2026-06-07 11:08:59 +02:00
dev d1a7aa3f74 fix: use self-hosted runner
Build & Push / build (push) Has been cancelled
2026-06-07 11:06:54 +02:00
6 changed files with 1081 additions and 1067 deletions
+5 -8
View File
@@ -6,18 +6,15 @@ on:
jobs:
build:
runs-on: ubuntu-latest
runs-on: self-hosted
steps:
- uses: actions/checkout@v3
- name: Checkout
run: git clone https://gitea.it-microevo.com/Dev/k8s-pilot.git .
- name: Login to Gitea Registry
run: echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login gitea.it-microevo.com -u "${{ secrets.REGISTRY_USER }}" --password-stdin
- name: Build & Push
run: |
docker build -t gitea.it-microevo.com/Dev/k8s-pilot:latest .
docker push gitea.it-microevo.com/Dev/k8s-pilot:latest
- name: Rolling Restart
run: |
kubectl rollout restart deployment/k8s-pilot -n k8s-pilot
docker build -t gitea.it-microevo.com/dev/k8s-pilot:latest .
docker push gitea.it-microevo.com/dev/k8s-pilot:latest
+1 -1
View File
@@ -4,7 +4,7 @@ FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
RUN npm install --omit=dev
COPY src/ ./src/
+1 -1
View File
@@ -51,7 +51,7 @@ spec:
- name: k8s-pilot
# Replace with your Gitea registry path:
# image: git.it-microevo.com/<user>/k8s-pilot:latest
image: k8s-pilot:latest
image: gitea.it-microevo.com/dev/k8s-pilot:latest
imagePullPolicy: Always
ports:
- containerPort: 3000
+3
View File
@@ -23,6 +23,9 @@ rules:
- apiGroups: [""]
resources: ["events"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list"]
- apiGroups: ["apps"]
resources: ["deployments", "replicasets"]
verbs: ["get", "list", "watch", "patch", "update"]
+1004 -1057
View File
File diff suppressed because it is too large Load Diff
+67
View File
@@ -4,6 +4,9 @@ const { WebSocketServer } = require('ws');
const http = require('http');
const path = require('path');
const { PassThrough } = require('stream');
const zlib = require('zlib');
const { promisify } = require('util');
const gunzip = promisify(zlib.gunzip);
const fetch = require('node-fetch');
const app = express();
@@ -361,6 +364,70 @@ app.get('/api/vulnerabilities', async (req, res) => {
}
});
// Helm releases (reads helm.sh/release.v1 secrets)
app.get('/api/helm/releases', async (req, res) => {
try {
const result = await coreApi.listSecretForAllNamespaces();
const helmSecrets = result.body.items.filter(s => s.type === 'helm.sh/release.v1');
// Keep only latest revision per release
const latestMap = {};
for (const s of helmSecrets) {
const key = `${s.metadata.namespace}/${s.metadata.labels?.name}`;
const v = parseInt(s.metadata.labels?.version || '0');
if (!latestMap[key] || v > latestMap[key].v) latestMap[key] = { s, v };
}
const releases = [];
for (const { s } of Object.values(latestMap)) {
try {
const compressed = Buffer.from(s.data.release, 'base64');
const json = await gunzip(compressed);
const r = JSON.parse(json.toString());
releases.push({
name: r.name,
namespace: r.namespace,
status: r.info?.status,
chartName: r.chart?.metadata?.name,
chartVersion: r.chart?.metadata?.version,
appVersion: r.chart?.metadata?.appVersion,
description: r.chart?.metadata?.description,
deployedAt: r.info?.last_deployed,
revision: parseInt(s.metadata.labels?.version || '1'),
});
} catch (e) { console.error('[helm parse]', e.message); }
}
res.json(releases.sort((a, b) => a.name.localeCompare(b.name)));
} catch (err) {
console.error('[helm]', err.message);
res.status(500).json({ error: err.message });
}
});
// Check Artifact Hub for latest chart version
app.get('/api/helm/check-update/:chart', async (req, res) => {
const { chart } = req.params;
try {
const response = await fetch(
`https://artifacthub.io/api/v1/packages/search?ts_query_web=${encodeURIComponent(chart)}&kind=0&limit=10`
);
const data = await response.json();
const packages = data.packages || [];
const match = packages.find(p => p.name === chart) || packages[0];
if (!match) return res.json({ found: false });
res.json({
found: true,
latestVersion: match.version,
appVersion: match.app_version,
repoName: match.repository?.name,
artifactHubUrl: `https://artifacthub.io/packages/helm/${match.repository?.name}/${match.name}`,
});
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// ── SSE: Live log stream ──────────────────────────────────────────────────────
app.get('/api/logs/:namespace/:pod/:container', async (req, res) => {
const { namespace, pod, container } = req.params;