Zastava Architecture (Retired)
Scope. This is the public-facing retirement record for Zastava, the former Kubernetes admission/runtime-observation direction. Zastava is no longer a live Stella Ops surface; runtime posture and workload observation have been absorbed into the deployment agent (
StellaOps.Agent.Host). Read this if you are tracing the history ofStellaOps.Zastava.*, thezastava.*wire schema identifiers, or the reusedZastavaname. For the live replacement, see Replacement Architecture and../release-orchestrator/architecture.md. For the name-collision disambiguation (the live registry-webhook SBOM source type and the dead CLI stub), seeREADME.md.
FULLY RETIRED 2026-05-12 (SPRINT_20260512_018). The Zastava source tree (
StellaOps.Zastava.Agent,StellaOps.Zastava.Observer,StellaOps.Zastava.Webhook,StellaOps.Zastava.Core, all tests, and the module solution) has been moved todocs-archive/code-snapshots/zastava-2026-05-12-retired/. Thezastava-webhookcompose service (Slot 43) and Dockerfile stages are decommissioned. No live solution referencesStellaOps.Zastava.*projects anymore. This document is preserved as the public-facing retirement record.
Status
This architecture is retired for active Stella Ops implementation.
The previous Zastava design centered on Kubernetes admission and runtime observation patterns. That direction conflicts with the current product decision: Stella Ops does not support Kubernetes or Helm deployments.
Contract relocation note (Sprint 20260512_020): The runtime/admission DTOs previously housed at
src/Zastava/__Libraries/StellaOps.Zastava.Core/Contracts/were moved to the neutral librarysrc/ReleaseOrchestrator/__Libraries/StellaOps.Runtime.Contracts/under namespaceStellaOps.Runtime.Contracts. The static class formerly namedZastavaContractVersionsis nowRuntimeContractVersions. The schema STRING identifiers on the wire (zastava.runtime.event@v1,zastava.admission.decision@v1) are unchanged for backward compatibility with deployed Scanner.WebService consumers. The transitionalStellaOps.Zastava.CoreProjectReference toStellaOps.Runtime.Contractswas dropped in SPRINT_20260512_018 (ZA-ARCH-004) when the whole Zastava tree was archived.
Replacement Architecture
Runtime posture and workload observation are now absorbed into the deployment agent (StellaOps.Agent.Host) rather than a separate host-agent product per the Sprint 20260512_020 design decision. The agent that already ships, gets provisioned with mTLS certs, and runs as stellaops-agent-core on .10/.20 also carries the runtime.observe.container capability that emits RuntimeEvidenceEnvelope payloads to BOTH Signals (signals.runtime_facts) and the Findings Ledger (findings.runtime_traces). Both downstream tables gained a nullable release_id column in this sprint so runtime evidence can be tied to a deployed release without cross-schema joins.
Legacy references (kept for completeness, no longer load-bearing):
- Linux host agent (
src/RuntimeInstrumentation/StellaOps.Agent.Linux/). - Windows host agent (
src/RuntimeInstrumentation/StellaOps.Agent.Windows/). - Shared Agent.Core contracts (
src/RuntimeInstrumentation/StellaOps.Agent.Core/). - Optional Linux sensor inputs such as Tetragon.
- Digest-gated evidence publication.
See:
../release-orchestrator/architecture.md— authoritative, unified runtime-observation section.docs-archive/implplan/SPRINT_20260512_020_ReleaseOrchestrator_runtime_observation_unification.md(archived) — the unification decision.../runtime-instrumentation/architecture.md— historical host-agent story; partially superseded by the unification.../runtime-instrumentation/host-agent-strategy.md— historical.
Guardrail
Do not restore Kubernetes admission webhook, DaemonSet, Kubernetes API watch, Helm chart, or kubectl workflows under Zastava. Any surviving runtime posture concept must be redesigned for non-Kubernetes host agents first.
CRI digest resolution (in-process, fail-closed) — ARCHIVED DESIGN
ARCHIVED / NOT LIVE. The components described in this section are not present in
src/. They were part of the now-retiredStellaOps.Zastava.Observerproject and live only in the archived snapshot atdocs-archive/code-snapshots/zastava-2026-05-12-retired/src/StellaOps.Zastava.Observer/ContainerRuntime/Cri/. No live solution referencesContainerRuntimePoller,ICriImageDigestResolver,CriImageDigestResolverFactory, or the CRI/kubelet resolvers below. The section is preserved as a historical design record; the kubelet pod-status fallback in particular is Kubernetes-specific and conflicts with the non-Kubernetes guardrail above. The fail-closed digest-resolution intent survives in the replacement architecture (theruntime.observe.containercapability and theRuntimeEvidenceEnvelope); the implementation below does not.
The archived StellaOps.Zastava.Observer components (the ContainerRuntimePoller, the CRI v1 client, and the runtime-facts emitter) were designed to obtain an authoritative (imageRef, imageId) tuple for every running container before publishing a runtime fact. Synthesising digests from container IDs, image names, or wall-clock timestamps was forbidden — the non-resolved state was first-class and was propagated downstream as fail-closed input for Signals/Scanner consumers.
Precedence
ContainerStatus(image_ref) ──┐
├─► CRI primary resolver ──► resolved (imageRef, imageId)
ImageStatus(image_spec) ─────┘ │
▼ (only on RuntimeReportedNoDigest)
kubelet pod-status fallback
(containerStatuses[*].imageID)
│
▼
not-resolved:<reason> (fail-closed)
CRI primary (
ContainerdCriDigestResolver,CriOCriDigestResolver,DockerCriDigestResolver).- Call
RuntimeService.ContainerStatus. Ifimage_refis digest-pinned or a barealgo:hextoken, resolve immediately. - Otherwise call
ImageService.ImageStatus(image_spec)and prefer the first parseable repo digest, then a digest-shaped image id. - Docker’s primary uses
IWindowsContainerRuntimeClientand reads the inspect endpoint’sImage(image id) andConfig.Image(ref) fields.
- Call
Kubelet pod-status fallback (
KubeletPodStatusFallbackResolver).- Activates only when the primary returned
NotResolvedReason.RuntimeReportedNoDigest. Other reasons (RuntimeUnreachable,ContainerNotFound) are surfaced unchanged so the fallback never papers over runtime errors. - Reads
containerStatuses[*].imageIDfrom the Kubernetes pod-status view (host-agent kubelet client, registered asIKubernetesPodStatusReader). If the field is empty the originalRuntimeReportedNoDigestis preserved — there is no further escalation.
- Activates only when the primary returned
Not-resolved marker. When neither layer produces a digest, the runtime-facts envelope’s
Workload.ImageRefis set to a stable lowercase marker:not-resolved:runtime-unreachablenot-resolved:container-not-foundnot-resolved:runtime-reported-no-digestnot-resolved:digest-malformed
The envelope also carries
runtime.image.digestSource = not-resolvedandruntime.image.notResolvedReason = <marker>evidence entries so downstream Signals/Scanner consumers treat the workload as evaluation-incomplete and deny it under fail-closed posture.
The (archived) interface contract is at docs-archive/code-snapshots/zastava-2026-05-12-retired/src/StellaOps.Zastava.Observer/ContainerRuntime/Cri/ICriImageDigestResolver.cs and the runtime selection was in CriImageDigestResolverFactory.cs (same archived directory).
