Builder SoC (builder/context.go):
- Moved generateDockerfile, runtimeBaseImage, zipToTarGz from handler/upload.go
to internal/builder/context.go.
Reason: knowledge about runtime images and build context structure is a
build concern, not an HTTP handler concern.
- Added PrepareContext(zipData []byte, runtime string) (*bytes.Buffer, error) —
single public entry point. Handler calls one function, gets ready buffer.
- zipToTarGz now accepts *zip.Reader instead of []byte to avoid double parsing.
- upload.go reduced from ~200 LOC to ~60 LOC (build logic gone).
auth.go — JWKS insertion point:
- Added verifySignature() stub with detailed comment explaining what v2
implementation needs (JWKS endpoint, kid lookup, RS256/ES256 verify).
- Shows exactly where to add the call in validateJWT.
Unit tests (9 total, all pass):
- controllers: TestBuildDeployment_EnvVarsSorted, TestBuildDeployment_EmptyEnv
- handler: TestHopByHopHeaders_* (3 tests)
- builder: TestPrepareContext_PythonWithRequirements, _NodeNoPackageJSON,
_UnsupportedRuntime, _DockerfileIsFirst
- trigger: CronJob moved to deployNS (sless-fn-{userNS}), was tr.Namespace
Reason: with NetworkPolicy default-deny, pod in user-ns can't reach
Service in sless-fn-ns. Co-locating CronJob with Service guarantees
connectivity regardless of NetworkPolicy configuration.
handleTriggerDeletion updated consistently.
- trigger: pin curlimages/curl to 8.5.0 (was :latest)
Reason: reproducibility, no unexpected behavior changes from image updates.
- function: sort env vars in buildDeployment (was non-deterministic map range)
Reason: non-deterministic order caused k8s to detect container spec 'change'
on every reconcile → unnecessary pod restarts. Sorted order is stable.
- function: cleanup kaniko Job in handleDeletion
Reason: if Function deleted during Building phase, kaniko Job continued
running, wasting CPU/memory and pushing an unused image.
- invoke: filter hop-by-hop headers in proxy response (RFC 2616 §13.5.1)
Reason: Transfer-Encoding especially dangerous — forwarding it corrupts
response body framing for the client.
- config: SLESS_API_TOKEN no longer required
Reason: dead code — field loaded but never passed to any component.
Auth uses validateJWT() middleware, not static token.
Namespace lifecycle: user namespaces preserved on destroy (not changed).
E2E: apply 4 resources + destroy clean. Operator v0.1.22 deployed.
- TriggerReconciler: RequeueAfter 15s когда Function не Ready
(ранее зависал без повторного reconcile)
- FunctionJobReconciler: RequeueAfter 15s когда Function не Ready
- UpdateFunction: добавлена валидация runtime/entrypoint/memory_mb
(ранее мог затереть spec нулями при частичном обновлении)
- CronJob: curlimages/curl:latest → curlimages/curl:8.5.0 (pin version)
- Config: удалён FunctionNamespacePrefix (мёртвое поле, нигде не использовалось)
- Invocations endpoint: возвращает 501 вместо пустого списка
(SaveInvocation нигде не вызывается — честный ответ клиенту)
- Собран образ naeel/sless-operator:v0.1.19
- controllers/trigger_controller.go: handleTriggerDeletion теперь удаляет Service
и Ingress из sless-fn-{ns} при удалении HTTP-триггера
- controllers/function_controller.go: handleDeletion теперь удаляет Service и Ingress
(имена совпадают с fn.Name); добавлен импорт netv1
- terraform/provider trigger_resource.go: Delete ждёт пока GetTrigger вернёт 404
(до 90с) — провайдер не возвращает успех раньше чем cleanup завершён
- examples: версия провайдера обновлена до ~> 0.1.11
Operator: naeel/sless-operator:v0.1.17
Provider: v0.1.11
Fixes DESTROY_ROUTE_CLEANUP_BUG.md