From 2a00b2584045259262c4b20f9b6faf21f82e312c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zo=C3=AB?= Date: Sat, 30 May 2026 20:26:32 -0700 Subject: [PATCH] feat: intake service - HTTP endpoint to submit tasks to Janet --- .woodpecker.yaml | 21 +++++ intake/Dockerfile | 14 ++++ intake/requirements.txt | 4 + k8s/externalsecrets/intake-vikunja-token.yaml | 21 +++++ k8s/manifests/intake-deployment.yaml | 79 +++++++++++++++++++ k8s/manifests/intake-ingress.yaml | 18 +++++ 6 files changed, 157 insertions(+) create mode 100644 intake/Dockerfile create mode 100644 intake/requirements.txt create mode 100644 k8s/externalsecrets/intake-vikunja-token.yaml create mode 100644 k8s/manifests/intake-deployment.yaml create mode 100644 k8s/manifests/intake-ingress.yaml diff --git a/.woodpecker.yaml b/.woodpecker.yaml index ce307e0..e6c026b 100644 --- a/.woodpecker.yaml +++ b/.woodpecker.yaml @@ -54,6 +54,27 @@ steps: branch: mainline - event: tag + # ── Intake image ───────────────────────────────────────────────────────────── + - name: build-intake + image: woodpeckerci/plugin-docker-buildx + settings: + registry: registry.ctz.fyi + repo: registry.ctz.fyi/library/autojanet-intake + dockerfile: intake/Dockerfile + context: intake/ + username: + from_secret: RS_HARBOR_USER + password: + from_secret: RS_HARBOR_PASS + tags: + - latest + - "${CI_COMMIT_SHA:0:12}" + platforms: linux/amd64 + when: + - event: push + branch: mainline + - event: tag + # ── Trivy scan agent image ─────────────────────────────────────────────────── - name: trivy-agent image: aquasec/trivy:latest diff --git a/intake/Dockerfile b/intake/Dockerfile new file mode 100644 index 0000000..83dcbd2 --- /dev/null +++ b/intake/Dockerfile @@ -0,0 +1,14 @@ +FROM python:3.12-slim + +WORKDIR /app + +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +COPY main.py . + +RUN useradd -m -u 1000 intake +USER intake + +EXPOSE 8080 +CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8080"] diff --git a/intake/requirements.txt b/intake/requirements.txt new file mode 100644 index 0000000..c3a4ff5 --- /dev/null +++ b/intake/requirements.txt @@ -0,0 +1,4 @@ +fastapi==0.115.0 +uvicorn[standard]==0.30.6 +httpx==0.27.2 +pydantic==2.8.2 diff --git a/k8s/externalsecrets/intake-vikunja-token.yaml b/k8s/externalsecrets/intake-vikunja-token.yaml new file mode 100644 index 0000000..038c023 --- /dev/null +++ b/k8s/externalsecrets/intake-vikunja-token.yaml @@ -0,0 +1,21 @@ +--- +# ExternalSecret: intake-vikunja-token +# Pulls pm vikunja token from OpenBao for the intake service +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: intake-vikunja-token + namespace: autojanet +spec: + refreshInterval: 1h + secretStoreRef: + name: openbao + kind: ClusterSecretStore + target: + name: intake-vikunja-token + creationPolicy: Owner + data: + - secretKey: token + remoteRef: + key: autojanet/pm/vikunja-token + property: token diff --git a/k8s/manifests/intake-deployment.yaml b/k8s/manifests/intake-deployment.yaml new file mode 100644 index 0000000..98d9da6 --- /dev/null +++ b/k8s/manifests/intake-deployment.yaml @@ -0,0 +1,79 @@ +--- +# AutoJanet Intake Service +# Accepts task submissions via HTTP and creates Vikunja tasks with agent labels. +apiVersion: apps/v1 +kind: Deployment +metadata: + name: intake + namespace: autojanet + labels: + autojanet/role: intake +spec: + replicas: 1 + selector: + matchLabels: + autojanet/role: intake + template: + metadata: + labels: + autojanet/role: intake + spec: + serviceAccountName: intake + containers: + - name: intake + image: registry.ctz.fyi/library/autojanet-intake:latest + imagePullPolicy: Always + ports: + - containerPort: 8080 + env: + - name: VIKUNJA_BASE_URL + value: "http://vikunja.vikunja.svc.cluster.local:3456" + - name: VIKUNJA_PROJECT_ID + value: "78" + - name: VIKUNJA_TODO_BUCKET_ID + value: "116" + - name: VIKUNJA_VIEW_ID + value: "114" + - name: VIKUNJA_PM_TOKEN + valueFrom: + secretKeyRef: + name: intake-vikunja-token + key: token + resources: + requests: + cpu: "50m" + memory: "64Mi" + limits: + cpu: "200m" + memory: "128Mi" + livenessProbe: + httpGet: + path: /health + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 15 + securityContext: + allowPrivilegeEscalation: false + runAsNonRoot: true + runAsUser: 1000 + readOnlyRootFilesystem: true + capabilities: + drop: ["ALL"] +--- +apiVersion: v1 +kind: Service +metadata: + name: intake + namespace: autojanet +spec: + selector: + autojanet/role: intake + ports: + - port: 80 + targetPort: 8080 +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: intake + namespace: autojanet diff --git a/k8s/manifests/intake-ingress.yaml b/k8s/manifests/intake-ingress.yaml new file mode 100644 index 0000000..1f0059b --- /dev/null +++ b/k8s/manifests/intake-ingress.yaml @@ -0,0 +1,18 @@ +--- +# IngressRoute: janet.ctz.fyi → intake service +apiVersion: traefik.io/v1alpha1 +kind: IngressRoute +metadata: + name: intake + namespace: autojanet +spec: + entryPoints: + - websecure + routes: + - match: Host(`janet.ctz.fyi`) + kind: Rule + services: + - name: intake + port: 80 + tls: + certResolver: letsencrypt