What the API step needs from the operator
The operator step is complete. This is the contract the api/ component builds on.
Objects and fields the API reads and writes
| Object | The API writes | The API reads |
|---|---|---|
| Baseline | spec on connect and promote: application, workspace, source (git url, ref, path, kind, secretRef, helm values, pollInterval), entrypoint, inline services overrides, imageRegistry |
status.phase, status.source (commit, resolvedAt, renderedAt), status.resolvedServices, status.renderWarnings, status.routes, status.baselineHost, conditions Ready, RoutingReady, IngressTLS, SourceResolved, Rendered |
| Environment | spec.baselineRef, owner, workspace, ref, overrides[], ttl (extend = raise it), sleepAfterIdle, sharers, terminal |
status.phase (Pending, Deploying, Ready, Sleeping, Expired, Failed), namespace, previewURL, headerRule, services[] with mode copy or shared, expiresAt, deleteAt, lastActivity, sleptAt, conditions Ready, TTL |
| Policy | all of spec: workspaces, maxEnvironmentsPerUser, maxEnvironmentsPerWorkspace, quota, defaultRequests, defaultLimits, defaultTTL, maxTTL, sleepAfterIdle, expiredGracePeriod, allowedRegistries, requireRegistryMirror, terminalEnabled, allowedSourceKinds |
nothing yet |
Git credentials are Secrets in the application namespace with keys token/username,
ssh-privatekey/known_hosts/passphrase, ca.crt. The API must label them
nazeel.sa/git-credentials=true; the operator's RBAC covers only labelled Secrets and
reports a clear condition when the label is missing.
Admission errors to render
Environment writes rejected by the webhook return HTTP 422 with details.causes[]. Each
cause has field and message = <key> <json params>. Render with
api/v1alpha1.Messages[key] in the caller's language, interpolating {param}; the helper
internal/admission.Render shows the exact algorithm. Keys: nazeel.env.baseline.notFound,
nazeel.env.baseline.notRendered, nazeel.env.override.unknownService,
nazeel.env.override.sharedService, nazeel.env.override.registryNotAllowed,
nazeel.env.ttl.exceedsMax, nazeel.env.ttl.invalid, nazeel.env.sleepAfterIdle.invalid,
nazeel.env.quota.perUser, nazeel.env.quota.perWorkspace,
nazeel.env.terminal.disabledByPolicy, nazeel.env.field.immutable.
Events to ingest into the audit log
Watch events.k8s.io/v1 Events with reportingController nazeel.sa/operator or
nazeel.sa/router. Every lifecycle transition is one Event with its own timestamp:
| Regarding | Reason | Type |
|---|---|---|
| Environment | Expired, ExpiryExtended, TTLCapped, ExpiredDeleted, Sleeping, Woken, WakeTimeout |
Normal / Warning |
| Baseline | UnknownEnvironment (a request named an environment that does not exist) |
Warning |
The note carries the human-readable detail; action is stable (Expire, ExtendTTL,
CapTTL, Delete, Sleep, Wake, Route). Hash-chain them in the API's append-only log.
Rules the API must own
- Who may extend a TTL. The operator honours any
spec.ttlraise within the Policy maximum; RBAC (owner or Team lead) is the API's job. - Preview URL authentication. Preview hosts are open at the edge. Put SSO in front of
<env>--<app>.<domain>and<app>.<domain>, or front the router edge Service. - Terminal sessions. Only on the developer's own environment, never the baseline;
re-check
Policy.terminalEnabledat session time; record every session. The operator only refusesspec.terminalwhen the Policy forbids it. - Team quotas across namespaces. The webhook counts per namespace. If a team spans several application namespaces, aggregate in the API.
- Licence. Seats, expiry and features are validated by the API from the offline ed25519 licence. The operator never deletes environments for licence reasons; nothing in it depends on licence state today.
Operational facts the API should expose
- Routing header
X-Nazeel-Env: <environment>; the router also accepts and sets the W3C baggage membernazeel-env. Response headerX-Nazeel-Upstream: copy|baseline|router. - Router metrics on the router Service port 9090:
nazeel_router_requests_total,nazeel_router_request_duration_seconds,nazeel_router_unknown_env_total,nazeel_router_edge_headers_dropped_total,nazeel_router_wake_timeouts_total. - Operator flags the chart must surface:
--ingress-domain,--ingress-class,--ingress-tls-secret,--cluster-domain,--source-cache-dir,--source-concurrency,--webhook-cert-mode,--router-image(defaults to the operator image). - A Baseline with a git source shows
Rendered=False/Renderingfor a few seconds after connect; the Environment API should surfaceBaselineNotFoundwith the "not rendered yet" message rather than treating it as an error.
Not in the operator (follow-ups)
Supporting objects rendered from git (ConfigMaps, Secrets, volumes, probes, sidecars); inferring the environment from the caller's pod IP when no header is propagated; drift detection between the baseline commit and the tracked branch; cross-namespace quotas.