fix(worker): seal coordinator Python dependencies

This commit is contained in:
DCCONSTRUCTIONS
2026-08-31 21:31:45 +03:00
parent 0fcd037e4f
commit e958729e9d
8 changed files with 956 additions and 55 deletions
@@ -2,9 +2,14 @@ FROM nvcr.io/nvidia/tritonserver:26.06-py3@sha256:58df7489c3f2276f9591d500a012de
ARG NODEDC_SOURCE_REVISION
ARG NODEDC_BUILD_CONTEXT_SHA256
ARG NODEDC_PYTHON_DEPENDENCY_BUNDLE_SHA256
ARG NODEDC_PYTHON_DEPENDENCY_BUNDLE_FILE_COUNT
ARG NODEDC_PYTHON_DEPENDENCY_BUNDLE_BYTE_LENGTH
ARG NODEDC_PYTHON_DEPENDENCY_BUNDLE_MANIFEST_SHA256
ARG NODEDC_PYTHON_DEPENDENCY_BUNDLE_MANIFEST_BYTE_LENGTH
ARG SOURCE_DATE_EPOCH
ENV PYTHONPATH=/opt/nodedc/mission-core/src \
ENV PYTHONPATH=/opt/nodedc/mission-core/src:/opt/nodedc/mission-core/deps \
PYTHONNOUSERSITE=1 \
PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
@@ -14,6 +19,12 @@ WORKDIR /opt/nodedc/mission-core
COPY src/k1link ./src/k1link
COPY experiments/perception/worker/observatory_portable/worker-006-agent-build-context.json \
./release/worker-006-agent-build-context.json
# Evidence-only mirror of the exact-layer installer contract: these two inputs are
# materialized from the separately sealed build-only dependency bundle. They are
# embedded in the image and must never be supplied as runtime bind mounts.
COPY python-dependency-bundle ./deps
COPY worker-006-agent-python-dependency-bundle.json \
./release/worker-006-agent-python-dependency-bundle.json
RUN mkdir -p /run/nodedc/registries \
&& chmod 0555 /run/nodedc /run/nodedc/registries \
@@ -27,6 +38,31 @@ RUN mkdir -p /run/nodedc/registries \
* ) ;; \
esac \
&& test "${#NODEDC_BUILD_CONTEXT_SHA256}" -eq 64 \
&& case "${NODEDC_PYTHON_DEPENDENCY_BUNDLE_SHA256}" in \
*[!0-9a-f]* ) exit 64 ;; \
* ) ;; \
esac \
&& test "${#NODEDC_PYTHON_DEPENDENCY_BUNDLE_SHA256}" -eq 64 \
&& case "${NODEDC_PYTHON_DEPENDENCY_BUNDLE_FILE_COUNT}" in \
''|*[!0-9]* ) exit 64 ;; \
* ) ;; \
esac \
&& test "${NODEDC_PYTHON_DEPENDENCY_BUNDLE_FILE_COUNT}" -gt 0 \
&& case "${NODEDC_PYTHON_DEPENDENCY_BUNDLE_BYTE_LENGTH}" in \
''|*[!0-9]* ) exit 64 ;; \
* ) ;; \
esac \
&& test "${NODEDC_PYTHON_DEPENDENCY_BUNDLE_BYTE_LENGTH}" -gt 0 \
&& case "${NODEDC_PYTHON_DEPENDENCY_BUNDLE_MANIFEST_SHA256}" in \
*[!0-9a-f]* ) exit 64 ;; \
* ) ;; \
esac \
&& test "${#NODEDC_PYTHON_DEPENDENCY_BUNDLE_MANIFEST_SHA256}" -eq 64 \
&& case "${NODEDC_PYTHON_DEPENDENCY_BUNDLE_MANIFEST_BYTE_LENGTH}" in \
''|*[!0-9]* ) exit 64 ;; \
* ) ;; \
esac \
&& test "${NODEDC_PYTHON_DEPENDENCY_BUNDLE_MANIFEST_BYTE_LENGTH}" -gt 0 \
&& case "${SOURCE_DATE_EPOCH}" in \
''|*[!0-9]* ) exit 64 ;; \
* ) ;; \
@@ -48,7 +84,12 @@ LABEL org.opencontainers.image.title="NODE.DC Observatory Worker 006 agent" \
com.nodedc.models="external" \
com.nodedc.runtime-registries="external-read-only" \
com.nodedc.base-image.sha256="58df7489c3f2276f9591d500a012dee03e23d35543ce3c390b4c001e6bf90794" \
com.nodedc.build-context.sha256="${NODEDC_BUILD_CONTEXT_SHA256}"
com.nodedc.build-context.sha256="${NODEDC_BUILD_CONTEXT_SHA256}" \
com.nodedc.python-dependency-bundle.sha256="${NODEDC_PYTHON_DEPENDENCY_BUNDLE_SHA256}" \
com.nodedc.python-dependency-bundle.file-count="${NODEDC_PYTHON_DEPENDENCY_BUNDLE_FILE_COUNT}" \
com.nodedc.python-dependency-bundle.byte-length="${NODEDC_PYTHON_DEPENDENCY_BUNDLE_BYTE_LENGTH}" \
com.nodedc.python-dependency-bundle.manifest.sha256="${NODEDC_PYTHON_DEPENDENCY_BUNDLE_MANIFEST_SHA256}" \
com.nodedc.python-dependency-bundle.manifest.byte-length="${NODEDC_PYTHON_DEPENDENCY_BUNDLE_MANIFEST_BYTE_LENGTH}"
# The current private token and sealed release mounts are provisioned for root.
# Runtime confinement is mandatory in the install plan: read-only rootfs,
@@ -10,7 +10,15 @@ param(
[Parameter(Mandatory = $true)]
[ValidatePattern("^[a-f0-9]{64}$")]
[string]$ExpectedStagedSnapshotSha256
[string]$ExpectedStagedSnapshotSha256,
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[string]$DependencyBundleRoot,
[Parameter(Mandatory = $true)]
[ValidatePattern("^[a-f0-9]{64}$")]
[string]$ExpectedDependencyBundleSha256
)
Set-StrictMode -Version Latest
@@ -21,6 +29,7 @@ $RuntimeRoot = [IO.Path]::GetFullPath("D:\NDC_MISSIONCORE\runtime").TrimEnd("\")
$StagedSnapshotRoot = Join-Path (
$RuntimeRoot
) "staging\observatory-worker-agent-$SourceRevision"
$DependencyBundleRoot = [IO.Path]::GetFullPath($DependencyBundleRoot).TrimEnd("\")
$ContextManifestRelativePath = (
"experiments/perception/worker/observatory_portable/" +
"worker-006-agent-build-context.json"
@@ -30,6 +39,9 @@ $DockerfileRelativePath = (
"Dockerfile.worker-006-agent"
)
$SourceTreeRelativePath = "src/k1link"
$DependencyManifestImagePath = (
"/opt/nodedc/mission-core/release/worker-006-agent-python-dependency-bundle.json"
)
$BaseImageSha256 = (
"58df7489c3f2276f9591d500a012dee03e23d35543ce3c390b4c001e6bf90794"
)
@@ -40,11 +52,37 @@ $ImageWorkdir = "/opt/nodedc/mission-core"
$ImageEntrypoint = '["python3","-m","k1link.observatory.m49_worker_container_main"]'
$ImageCommand = '[]'
$FixedEnvironment = @(
"PYTHONPATH=/opt/nodedc/mission-core/src",
"PYTHONPATH=/opt/nodedc/mission-core/src:/opt/nodedc/mission-core/deps",
"PYTHONNOUSERSITE=1",
"PYTHONDONTWRITEBYTECODE=1",
"PYTHONUNBUFFERED=1"
)
$PythonSmokeProgram = (
"from importlib.metadata import version; " +
"expected={" +
"`"httpx`":`"0.28.1`"," +
"`"lz4`":`"4.4.5`"," +
"`"paho-mqtt`":`"2.1.0`"," +
"`"PyYAML`":`"6.0.3`"," +
"`"typing_extensions`":`"4.16.0`"}; " +
"assert all(version(name) == wanted for name,wanted in expected.items()); " +
"import httpx; import lz4.frame; import paho.mqtt.client as mqtt; " +
"import typing_extensions; import yaml; " +
"payload=b`"worker-006-offline`"; " +
"assert lz4.frame.decompress(lz4.frame.compress(payload)) == payload; " +
"url=httpx.URL(`"https://offline.invalid/probe`",params={`"worker`":`"006`"}); " +
"request=httpx.Request(`"GET`",url); " +
"assert request.url.params[`"worker`"] == `"006`"; " +
"document={`"worker`":6,`"offline`":True}; " +
"assert yaml.safe_load(yaml.safe_dump(document)) == document; " +
"client=mqtt.Client(callback_api_version=mqtt.CallbackAPIVersion.VERSION2); " +
"client.user_data_set(document); " +
"assert typing_extensions.TypeAlias is not None; " +
"import k1link.observatory.m49_worker_container_main as entrypoint; " +
"import k1link.observatory.m49_worker_service as composition; " +
"assert callable(entrypoint.main); " +
"assert callable(composition.compose_installed_m49_worker_service)"
)
function Get-FileSha256 {
param([string]$Path)
@@ -54,7 +92,7 @@ function Get-FileSha256 {
-not ($item -is [IO.FileInfo]) -or
($item.Attributes -band [IO.FileAttributes]::ReparsePoint)
) {
throw "Worker 006 staged source is not a regular file"
throw "Worker 006 installation input is not a regular file"
}
return (Get-FileHash -LiteralPath $item.FullName -Algorithm SHA256).Hash.ToLowerInvariant()
}
@@ -133,7 +171,7 @@ function Get-StagedSnapshotInspection {
$context = Get-Content -LiteralPath $manifestPath -Raw | ConvertFrom-Json
if (
[string]$context.schema_version -cne
"missioncore.observatory-worker-agent-build-context/v1" -or
"missioncore.observatory-worker-agent-build-context/v2" -or
[string]$context.worker_id -cne "worker-006" -or
[string]$context.base_image.sha256 -cne $BaseImageSha256 -or
[bool]$context.base_image.pull_allowed
@@ -153,6 +191,40 @@ function Get-StagedSnapshotInspection {
) {
throw "Worker 006 staged build-context entries changed"
}
$externalBuildInputs = @($context.external_build_inputs)
if ($externalBuildInputs.Count -ne 1) {
throw "Worker 006 staged dependency build-input contract changed"
}
$dependencyInput = $externalBuildInputs[0]
$expectedDependencyProvenance = (
"already-proven Python dependency tree from the previously accepted " +
"Worker; build input only"
)
if (
[string]$dependencyInput.role -cne "python-dependency-bundle" -or
-not [bool]$dependencyInput.required -or
[string]$dependencyInput.provenance_requirement -cne
$expectedDependencyProvenance -or
[string]$dependencyInput.image_path -cne
"/opt/nodedc/mission-core/deps" -or
[string]$dependencyInput.manifest_image_path -cne
$DependencyManifestImagePath -or
[string]$dependencyInput.manifest_schema_version -cne
"missioncore.observatory-worker-agent-python-dependency-bundle/v1" -or
[string]$dependencyInput.identity.canonicalization -cne
"utf8-path-nul-length-nul-sha256-lf-v1" -or
[string]$dependencyInput.identity.path_order -cne "ordinal" -or
[bool]$dependencyInput.included_in_git_archive -or
-not [bool]$dependencyInput.copied_into_image -or
[bool]$dependencyInput.runtime_bind_allowed -or
[bool]$dependencyInput.network_install_allowed -or
[string]$context.runtime.pythonpath -cne
"/opt/nodedc/mission-core/src:/opt/nodedc/mission-core/deps" -or
-not [bool]$context.runtime.python_dependency_bundle_baked_into_image -or
[bool]$context.runtime.python_dependency_bundle_runtime_bind_allowed
) {
throw "Worker 006 staged dependency build-input contract is invalid"
}
$files = New-Object "Collections.Generic.List[object]"
foreach ($item in $sourceItems) {
@@ -163,20 +235,28 @@ function Get-StagedSnapshotInspection {
$files.Add((Get-Item -LiteralPath $dockerfilePath -Force))
$files.Add((Get-Item -LiteralPath $manifestPath -Force))
$rows = New-Object "Collections.Generic.List[object]"
$rowsByPath = @{}
foreach ($file in $files) {
$relative = $file.FullName.Substring($Root.Length).TrimStart("\")
$relative = $relative.Replace("\", "/")
if (-not $relative -or $relative -match "[\x00\r\n]") {
if (
-not $relative -or
$relative -match "[\x00\r\n]" -or
$rowsByPath.ContainsKey($relative)
) {
throw "Worker 006 staged snapshot path is invalid"
}
$rows.Add([pscustomobject]@{
$rowsByPath.Add($relative, [pscustomobject]@{
path = $relative
byte_length = [int64]$file.Length
sha256 = Get-FileSha256 $file.FullName
})
}
$orderedRows = @($rows | Sort-Object -Property path -CaseSensitive)
$orderedPaths = [string[]]@($rowsByPath.Keys)
[Array]::Sort($orderedPaths, [StringComparer]::Ordinal)
$orderedRows = @(
$orderedPaths | ForEach-Object { $rowsByPath[$_] }
)
$canonical = New-Object Text.StringBuilder
[int64]$totalBytes = 0
foreach ($row in $orderedRows) {
@@ -207,6 +287,92 @@ function Get-StagedSnapshotInspection {
}
}
function Get-DependencyBundleInspection {
param([string]$Root)
$rootItem = Get-Item -LiteralPath $Root -Force
if (
-not ($rootItem -is [IO.DirectoryInfo]) -or
($rootItem.Attributes -band [IO.FileAttributes]::ReparsePoint)
) {
throw "Worker 006 Python dependency bundle root is invalid"
}
$items = @(Get-ChildItem -LiteralPath $rootItem.FullName -Recurse -Force)
if ($items.Count -eq 0) {
throw "Worker 006 Python dependency bundle is empty"
}
$files = New-Object "Collections.Generic.List[object]"
foreach ($item in $items) {
if ($item.Attributes -band [IO.FileAttributes]::ReparsePoint) {
throw "Worker 006 Python dependency bundle contains a reparse point"
}
if ($item -is [IO.FileInfo]) {
$files.Add($item)
continue
}
if (-not ($item -is [IO.DirectoryInfo])) {
throw "Worker 006 Python dependency bundle contains a non-file entry"
}
}
if ($files.Count -eq 0) {
throw "Worker 006 Python dependency bundle contains no regular files"
}
$rowsByPath = @{}
foreach ($file in $files) {
$relative = $file.FullName.Substring($rootItem.FullName.Length).TrimStart("\")
$relative = $relative.Replace("\", "/")
if (
-not $relative -or
$relative -match "[\x00\r\n]" -or
$rowsByPath.ContainsKey($relative)
) {
throw "Worker 006 Python dependency bundle path is invalid"
}
$rowsByPath.Add($relative, [pscustomobject]@{
path = $relative
byte_length = [int64]$file.Length
sha256 = Get-FileSha256 $file.FullName
})
}
$orderedPaths = [string[]]@($rowsByPath.Keys)
[Array]::Sort($orderedPaths, [StringComparer]::Ordinal)
$orderedRows = @(
$orderedPaths | ForEach-Object { $rowsByPath[$_] }
)
$canonical = New-Object Text.StringBuilder
[int64]$totalBytes = 0
foreach ($row in $orderedRows) {
[void]$canonical.Append([string]$row.path)
[void]$canonical.Append([char]0)
[void]$canonical.Append(
([int64]$row.byte_length).ToString([Globalization.CultureInfo]::InvariantCulture)
)
[void]$canonical.Append([char]0)
[void]$canonical.Append([string]$row.sha256)
[void]$canonical.Append("`n")
$totalBytes += [int64]$row.byte_length
}
$utf8 = New-Object Text.UTF8Encoding($false)
$canonicalBytes = $utf8.GetBytes($canonical.ToString())
$hasher = [Security.Cryptography.SHA256]::Create()
try {
$digestBytes = $hasher.ComputeHash($canonicalBytes)
}
finally {
$hasher.Dispose()
}
$digest = ([BitConverter]::ToString($digestBytes)).Replace("-", "").ToLowerInvariant()
return [pscustomobject]@{
sha256 = $digest
file_count = [int64]$orderedRows.Count
byte_length = $totalBytes
canonicalization = "utf8-path-nul-length-nul-sha256-lf-v1"
files = @($orderedRows)
}
}
function New-StagedSnapshotManifest {
param([object]$SnapshotInspection)
@@ -240,6 +406,46 @@ function New-StagedSnapshotManifest {
}
}
function New-DependencyBundleManifest {
param([object]$DependencyInspection)
$stagingRoot = Split-Path -Parent $StagedSnapshotRoot
$manifestPath = Join-Path (
$stagingRoot
) ("observatory-worker-agent-python-deps-{0}.json" -f [Guid]::NewGuid().ToString("N"))
$payload = [ordered]@{
schema_version = "missioncore.observatory-worker-agent-python-dependency-bundle/v1"
bundle_sha256 = [string]$DependencyInspection.sha256
canonicalization = [string]$DependencyInspection.canonicalization
file_count = [int64]$DependencyInspection.file_count
byte_length = [int64]$DependencyInspection.byte_length
required_distributions = [ordered]@{
httpx = "0.28.1"
lz4 = "4.4.5"
"paho-mqtt" = "2.1.0"
PyYAML = "6.0.3"
typing_extensions = "4.16.0"
}
files = @($DependencyInspection.files)
}
$json = $payload | ConvertTo-Json -Compress -Depth 5
$utf8 = New-Object Text.UTF8Encoding($false)
try {
[IO.File]::WriteAllText($manifestPath, $json, $utf8)
return [pscustomobject]@{
path = $manifestPath
sha256 = Get-FileSha256 $manifestPath
byte_length = [int64](Get-Item -LiteralPath $manifestPath -Force).Length
}
}
catch {
if (Test-Path -LiteralPath $manifestPath -PathType Leaf) {
Remove-Item -LiteralPath $manifestPath -Force
}
throw
}
}
function Get-ImageInspection {
param([string]$Reference)
@@ -258,10 +464,21 @@ function Assert-ImageContract {
param(
[object]$Image,
[object]$BaseImage,
[string]$EmbeddedManifestSha256
[string]$EmbeddedManifestSha256,
[object]$DependencyInspection,
[object]$DependencyManifest
)
$labels = $Image.Config.Labels
$dependencyFileCount = (
[int64]$DependencyInspection.file_count
).ToString([Globalization.CultureInfo]::InvariantCulture)
$dependencyByteLength = (
[int64]$DependencyInspection.byte_length
).ToString([Globalization.CultureInfo]::InvariantCulture)
$dependencyManifestByteLength = (
[int64]$DependencyManifest.byte_length
).ToString([Globalization.CultureInfo]::InvariantCulture)
$expectedLabels = [ordered]@{
"org.opencontainers.image.title" = "NODE.DC Observatory Worker 006 agent"
"org.opencontainers.image.source" = "NODEDC_MISSION_CORE"
@@ -278,6 +495,11 @@ function Assert-ImageContract {
"com.nodedc.build-context.sha256" = $ExpectedGitArchiveSha256
"com.nodedc.staged-snapshot.sha256" = $ExpectedStagedSnapshotSha256
"com.nodedc.embedded-snapshot-manifest.sha256" = $EmbeddedManifestSha256
"com.nodedc.python-dependency-bundle.sha256" = [string]$DependencyInspection.sha256
"com.nodedc.python-dependency-bundle.file-count" = $dependencyFileCount
"com.nodedc.python-dependency-bundle.byte-length" = $dependencyByteLength
"com.nodedc.python-dependency-bundle.manifest.sha256" = [string]$DependencyManifest.sha256
"com.nodedc.python-dependency-bundle.manifest.byte-length" = $dependencyManifestByteLength
"com.nodedc.build-method" = $BuildMethod
}
foreach ($key in $expectedLabels.Keys) {
@@ -342,7 +564,9 @@ function Invoke-InstalledImageSmoke {
param(
[string]$Tag,
[string]$SnapshotRoot,
[object]$EmbeddedManifest
[object]$EmbeddedManifest,
[string]$DependencyRoot,
[object]$DependencyManifest
)
$smokeScript = (
@@ -376,11 +600,34 @@ function Invoke-InstalledImageSmoke {
"for image_path do relative=`${image_path#/opt/nodedc/mission-core/}; " +
"cmp -s `"`$image_path`" `"/nodedc-verify-source/`$relative`" || exit 73; " +
"done' sh {} +; " +
"test -d /opt/nodedc/mission-core/deps; " +
"test -z `"`$(find /opt/nodedc/mission-core/deps -mindepth 1 " +
"! -type d ! -type f -print -quit)`"; " +
"test -z `"`$(find /nodedc-verify-deps -mindepth 1 " +
"! -type d ! -type f -print -quit)`"; " +
"cmp -s /nodedc-verify-deps-manifest.json " +
"$DependencyManifestImagePath; " +
"test `"`$(sha256sum $DependencyManifestImagePath | cut -d' ' -f1)`" = " +
"$($DependencyManifest.sha256); " +
"find /nodedc-verify-deps -mindepth 1 -type d -exec sh -c '" +
"for source_path do relative=`${source_path#/nodedc-verify-deps/}; " +
"test -d `"/opt/nodedc/mission-core/deps/`$relative`" || exit 74; " +
"done' sh {} +; " +
"find /opt/nodedc/mission-core/deps -mindepth 1 -type d -exec sh -c '" +
"for image_path do relative=`${image_path#/opt/nodedc/mission-core/deps/}; " +
"test -d `"/nodedc-verify-deps/`$relative`" || exit 75; " +
"done' sh {} +; " +
"find /nodedc-verify-deps -type f -exec sh -c '" +
"for source_path do relative=`${source_path#/nodedc-verify-deps/}; " +
"cmp -s `"`$source_path`" " +
"`"/opt/nodedc/mission-core/deps/`$relative`" || exit 76; " +
"done' sh {} +; " +
"find /opt/nodedc/mission-core/deps -type f -exec sh -c '" +
"for image_path do relative=`${image_path#/opt/nodedc/mission-core/deps/}; " +
"cmp -s `"`$image_path`" `"/nodedc-verify-deps/`$relative`" || exit 77; " +
"done' sh {} +; " +
"cd /opt/nodedc/mission-core; " +
"python3 -B -c 'import k1link.observatory.m49_worker_container_main as entrypoint; " +
"import k1link.observatory.m49_worker_service as composition; " +
"assert callable(entrypoint.main); " +
"assert callable(composition.compose_installed_m49_worker_service)'"
"python3 -B -c '$PythonSmokeProgram'"
)
$sourceMount = (
"type=bind,source=$SnapshotRoot," +
@@ -390,6 +637,14 @@ function Invoke-InstalledImageSmoke {
"type=bind,source=$($EmbeddedManifest.path)," +
"target=/nodedc-verify-snapshot.json,readonly"
)
$dependencyMount = (
"type=bind,source=$DependencyRoot," +
"target=/nodedc-verify-deps,readonly"
)
$dependencyManifestMount = (
"type=bind,source=$($DependencyManifest.path)," +
"target=/nodedc-verify-deps-manifest.json,readonly"
)
docker run `
--rm `
--network none `
@@ -399,6 +654,8 @@ function Invoke-InstalledImageSmoke {
--security-opt no-new-privileges `
--mount $sourceMount `
--mount $manifestMount `
--mount $dependencyMount `
--mount $dependencyManifestMount `
--entrypoint /bin/sh `
$Tag `
-c $smokeScript
@@ -414,11 +671,13 @@ function New-OutputContract {
[object]$Image,
[object]$LayerInspection,
[object]$SnapshotInspection,
[object]$EmbeddedManifest
[object]$EmbeddedManifest,
[object]$DependencyInspection,
[object]$DependencyManifest
)
return [ordered]@{
schema_version = "missioncore.observatory-worker-agent-image-installation/v1"
schema_version = "missioncore.observatory-worker-agent-image-installation/v2"
status = $Status
worker_id = "worker-006"
build_method = $BuildMethod
@@ -432,6 +691,12 @@ function New-OutputContract {
staged_snapshot_canonicalization = [string]$SnapshotInspection.canonicalization
embedded_snapshot_manifest_sha256 = [string]$EmbeddedManifest.sha256
embedded_snapshot_manifest_byte_length = [int64]$EmbeddedManifest.byte_length
python_dependency_bundle_sha256 = [string]$DependencyInspection.sha256
python_dependency_bundle_file_count = [int64]$DependencyInspection.file_count
python_dependency_bundle_byte_length = [int64]$DependencyInspection.byte_length
python_dependency_bundle_canonicalization = [string]$DependencyInspection.canonicalization
python_dependency_bundle_manifest_sha256 = [string]$DependencyManifest.sha256
python_dependency_bundle_manifest_byte_length = [int64]$DependencyManifest.byte_length
}
base_image_sha256 = $BaseImageSha256
derived_image_sha256 = ([string]$Image.Id).Substring(7)
@@ -450,11 +715,13 @@ function New-OutputContract {
}
runtime_contract = [ordered]@{
workdir = $ImageWorkdir
pythonpath = "/opt/nodedc/mission-core/src:/opt/nodedc/mission-core/deps"
entrypoint = @("python3", "-m", "k1link.observatory.m49_worker_container_main")
command = @()
authority = "observation-only"
models = "external"
runtime_registries = "external-read-only"
python_dependencies = "embedded-sealed-build-input"
}
smoke = [ordered]@{
network = "none"
@@ -462,6 +729,10 @@ function New-OutputContract {
staged_source_bytes = "matched"
embedded_context_bytes = "matched"
embedded_snapshot_manifest = "matched"
python_dependency_bundle_bytes = "matched"
python_dependency_bundle_manifest = "matched"
required_dependency_versions = "matched"
offline_dependency_operations = "passed"
result = "passed"
}
}
@@ -472,10 +743,31 @@ if (-not (Test-Path -LiteralPath $StagedSnapshotRoot -PathType Container)) {
}
$snapshotBefore = Get-StagedSnapshotInspection $StagedSnapshotRoot
if ([string]$snapshotBefore.sha256 -cne $ExpectedStagedSnapshotSha256) {
throw "Worker 006 staged snapshot identity changed"
throw (
"Worker 006 staged snapshot identity changed: observed=" +
[string]$snapshotBefore.sha256
)
}
$embeddedManifest = New-StagedSnapshotManifest $snapshotBefore
$dependencyRootItem = Get-Item -LiteralPath $DependencyBundleRoot -Force
if (
-not ($dependencyRootItem -is [IO.DirectoryInfo]) -or
($dependencyRootItem.Attributes -band [IO.FileAttributes]::ReparsePoint)
) {
throw "Worker 006 Python dependency bundle root is unavailable"
}
$DependencyBundleRoot = $dependencyRootItem.FullName.TrimEnd("\")
$dependencyBefore = Get-DependencyBundleInspection $DependencyBundleRoot
if ([string]$dependencyBefore.sha256 -cne $ExpectedDependencyBundleSha256) {
throw (
"Worker 006 Python dependency bundle identity changed: observed=" +
[string]$dependencyBefore.sha256
)
}
$embeddedManifest = $null
$dependencyManifest = $null
try {
$embeddedManifest = New-StagedSnapshotManifest $snapshotBefore
$dependencyManifest = New-DependencyBundleManifest $dependencyBefore
$base = Get-ImageInspection $BaseImageReference
if ([string]$base.Id -cne $BaseImageReference) {
throw "Worker 006 base image identity changed"
@@ -503,16 +795,25 @@ try {
$layerInspection = Assert-ImageContract `
$image `
$base `
([string]$embeddedManifest.sha256)
Invoke-InstalledImageSmoke $tag $StagedSnapshotRoot $embeddedManifest
([string]$embeddedManifest.sha256) `
$dependencyBefore `
$dependencyManifest
Invoke-InstalledImageSmoke `
$tag `
$StagedSnapshotRoot `
$embeddedManifest `
$DependencyBundleRoot `
$dependencyManifest
New-OutputContract `
"already-installed" `
$tag `
$image `
$layerInspection `
$snapshotBefore `
$embeddedManifest |
ConvertTo-Json -Compress -Depth 9
$embeddedManifest `
$dependencyBefore `
$dependencyManifest |
ConvertTo-Json -Compress -Depth 10
return
}
@@ -530,13 +831,16 @@ try {
$copyScript = (
"set -eu; " +
"test ! -e /opt/nodedc/mission-core; " +
"mkdir -p /opt/nodedc/mission-core/src /opt/nodedc/mission-core/release; " +
"mkdir -p /opt/nodedc/mission-core/src /opt/nodedc/mission-core/release " +
"/opt/nodedc/mission-core/deps; " +
"mkdir -p /run/nodedc/registries; " +
"cp -a /nodedc-build-source/src/k1link /opt/nodedc/mission-core/src/k1link; " +
"cp -a /nodedc-build-deps/. /opt/nodedc/mission-core/deps/; " +
"cp /nodedc-build-source/$ContextManifestRelativePath " +
"/opt/nodedc/mission-core/release/worker-006-agent-build-context.json; " +
"cp /nodedc-build-snapshot.json " +
"/opt/nodedc/mission-core/release/worker-006-agent-staged-snapshot.json; " +
"cp /nodedc-build-deps-manifest.json $DependencyManifestImagePath; " +
"find /nodedc-build-source/src/k1link -type f -exec sh -c '" +
"for source_path do relative=`${source_path#/nodedc-build-source/}; " +
"cmp -s `"`$source_path`" `"/opt/nodedc/mission-core/`$relative`" || exit 70; " +
@@ -545,17 +849,36 @@ try {
"/opt/nodedc/mission-core/release/worker-006-agent-build-context.json; " +
"cmp -s /nodedc-build-snapshot.json " +
"/opt/nodedc/mission-core/release/worker-006-agent-staged-snapshot.json; " +
"cmp -s /nodedc-build-deps-manifest.json $DependencyManifestImagePath; " +
"test -z `"`$(find /nodedc-build-deps -mindepth 1 " +
"! -type d ! -type f -print -quit)`"; " +
"test -z `"`$(find /opt/nodedc/mission-core/deps -mindepth 1 " +
"! -type d ! -type f -print -quit)`"; " +
"find /nodedc-build-deps -mindepth 1 -type d -exec sh -c '" +
"for source_path do relative=`${source_path#/nodedc-build-deps/}; " +
"test -d `"/opt/nodedc/mission-core/deps/`$relative`" || exit 71; " +
"done' sh {} +; " +
"find /opt/nodedc/mission-core/deps -mindepth 1 -type d -exec sh -c '" +
"for image_path do relative=`${image_path#/opt/nodedc/mission-core/deps/}; " +
"test -d `"/nodedc-build-deps/`$relative`" || exit 72; " +
"done' sh {} +; " +
"find /nodedc-build-deps -type f -exec sh -c '" +
"for source_path do relative=`${source_path#/nodedc-build-deps/}; " +
"cmp -s `"`$source_path`" " +
"`"/opt/nodedc/mission-core/deps/`$relative`" || exit 73; " +
"done' sh {} +; " +
"find /opt/nodedc/mission-core/deps -type f -exec sh -c '" +
"for image_path do relative=`${image_path#/opt/nodedc/mission-core/deps/}; " +
"cmp -s `"`$image_path`" `"/nodedc-build-deps/`$relative`" || exit 74; " +
"done' sh {} +; " +
"test ! -e /opt/nodedc/mission-core/experiments; " +
"find /opt/nodedc/mission-core -type d -exec chmod 0555 {} +; " +
"find /opt/nodedc/mission-core -type f -exec chmod 0444 {} +; " +
"chmod 0555 /run/nodedc /run/nodedc/registries; " +
"cd /opt/nodedc/mission-core; " +
"PYTHONPATH=/opt/nodedc/mission-core/src PYTHONNOUSERSITE=1 " +
"PYTHONDONTWRITEBYTECODE=1 python3 -B -c '" +
"import k1link.observatory.m49_worker_container_main as entrypoint; " +
"import k1link.observatory.m49_worker_service as composition; " +
"assert callable(entrypoint.main); " +
"assert callable(composition.compose_installed_m49_worker_service)'"
"PYTHONPATH=/opt/nodedc/mission-core/src:/opt/nodedc/mission-core/deps " +
"PYTHONNOUSERSITE=1 PYTHONDONTWRITEBYTECODE=1 " +
"python3 -B -c '$PythonSmokeProgram'"
)
$sourceMount = (
"type=bind,source=$StagedSnapshotRoot," +
@@ -565,6 +888,14 @@ try {
"type=bind,source=$($embeddedManifest.path)," +
"target=/nodedc-build-snapshot.json,readonly"
)
$dependencyMount = (
"type=bind,source=$DependencyBundleRoot," +
"target=/nodedc-build-deps,readonly"
)
$dependencyManifestMount = (
"type=bind,source=$($dependencyManifest.path)," +
"target=/nodedc-build-deps-manifest.json,readonly"
)
$containerId = $null
$imageCommitted = $false
$committedImageId = $null
@@ -578,6 +909,8 @@ try {
--security-opt no-new-privileges `
--mount $sourceMount `
--mount $manifestMount `
--mount $dependencyMount `
--mount $dependencyManifestMount `
--entrypoint /bin/sh `
$BaseImageReference `
-c $copyScript
@@ -606,6 +939,35 @@ try {
if ((Get-FileSha256 $embeddedManifest.path) -cne [string]$embeddedManifest.sha256) {
throw "Worker 006 embedded snapshot manifest changed during installation"
}
$dependencyAfter = Get-DependencyBundleInspection $DependencyBundleRoot
if (
[string]$dependencyAfter.sha256 -cne $ExpectedDependencyBundleSha256 -or
[int64]$dependencyAfter.file_count -ne
[int64]$dependencyBefore.file_count -or
[int64]$dependencyAfter.byte_length -ne
[int64]$dependencyBefore.byte_length
) {
throw (
"Worker 006 Python dependency bundle changed during installation: " +
"observed=" + [string]$dependencyAfter.sha256
)
}
if (
(Get-FileSha256 $dependencyManifest.path) -cne
[string]$dependencyManifest.sha256
) {
throw "Worker 006 Python dependency manifest changed during installation"
}
$dependencyFileCount = (
[int64]$dependencyBefore.file_count
).ToString([Globalization.CultureInfo]::InvariantCulture)
$dependencyByteLength = (
[int64]$dependencyBefore.byte_length
).ToString([Globalization.CultureInfo]::InvariantCulture)
$dependencyManifestByteLength = (
[int64]$dependencyManifest.byte_length
).ToString([Globalization.CultureInfo]::InvariantCulture)
$changes = @(
"--change", "WORKDIR $ImageWorkdir",
@@ -630,6 +992,26 @@ try {
"LABEL com.nodedc.embedded-snapshot-manifest.sha256=" +
[string]$embeddedManifest.sha256
),
"--change", (
"LABEL com.nodedc.python-dependency-bundle.sha256=" +
[string]$dependencyBefore.sha256
),
"--change", (
"LABEL com.nodedc.python-dependency-bundle.file-count=" +
$dependencyFileCount
),
"--change", (
"LABEL com.nodedc.python-dependency-bundle.byte-length=" +
$dependencyByteLength
),
"--change", (
"LABEL com.nodedc.python-dependency-bundle.manifest.sha256=" +
[string]$dependencyManifest.sha256
),
"--change", (
"LABEL com.nodedc.python-dependency-bundle.manifest.byte-length=" +
$dependencyManifestByteLength
),
"--change", "LABEL com.nodedc.build-method=$BuildMethod"
)
foreach ($value in $FixedEnvironment) {
@@ -663,16 +1045,25 @@ try {
$layerInspection = Assert-ImageContract `
$image `
$base `
([string]$embeddedManifest.sha256)
Invoke-InstalledImageSmoke $tag $StagedSnapshotRoot $embeddedManifest
([string]$embeddedManifest.sha256) `
$dependencyBefore `
$dependencyManifest
Invoke-InstalledImageSmoke `
$tag `
$StagedSnapshotRoot `
$embeddedManifest `
$DependencyBundleRoot `
$dependencyManifest
New-OutputContract `
"installed" `
$tag `
$image `
$layerInspection `
$snapshotBefore `
$embeddedManifest |
ConvertTo-Json -Compress -Depth 9
$embeddedManifest `
$dependencyBefore `
$dependencyManifest |
ConvertTo-Json -Compress -Depth 10
}
catch {
$installationFailure = $_
@@ -695,4 +1086,10 @@ finally {
) {
Remove-Item -LiteralPath $embeddedManifest.path -Force
}
if (
$null -ne $dependencyManifest -and
(Test-Path -LiteralPath $dependencyManifest.path -PathType Leaf)
) {
Remove-Item -LiteralPath $dependencyManifest.path -Force
}
}
@@ -78,7 +78,7 @@ INSTALLATION_EVIDENCE_SCHEMA: Final = (
"missioncore.observatory-portable-lab-v1-installation-evidence/v1"
)
WORKER_AGENT_IMAGE_INSTALLATION_SCHEMA: Final = (
"missioncore.observatory-worker-agent-image-installation/v1"
"missioncore.observatory-worker-agent-image-installation/v2"
)
LAB_V1_RELEASE_ID: Final = "lab-v1-eomt-ddrnet-worker006-candidate-v2"
LAB_V1_WORKER_AGENT_IMAGE_ASSET_ID: Final = "worker-006-agent-image"
@@ -1028,6 +1028,12 @@ def _load_installation_evidence(
"staged_snapshot_canonicalization",
"embedded_snapshot_manifest_sha256",
"embedded_snapshot_manifest_byte_length",
"python_dependency_bundle_sha256",
"python_dependency_bundle_file_count",
"python_dependency_bundle_byte_length",
"python_dependency_bundle_canonicalization",
"python_dependency_bundle_manifest_sha256",
"python_dependency_bundle_manifest_byte_length",
},
"coordinator provenance",
)
@@ -1060,11 +1066,13 @@ def _load_installation_evidence(
runtime,
{
"workdir",
"pythonpath",
"entrypoint",
"command",
"authority",
"models",
"runtime_registries",
"python_dependencies",
},
"coordinator runtime contract",
)
@@ -1077,6 +1085,10 @@ def _load_installation_evidence(
"staged_source_bytes",
"embedded_context_bytes",
"embedded_snapshot_manifest",
"python_dependency_bundle_bytes",
"python_dependency_bundle_manifest",
"required_dependency_versions",
"offline_dependency_operations",
"result",
},
"coordinator installation smoke",
@@ -1093,6 +1105,18 @@ def _load_installation_evidence(
provenance["embedded_snapshot_manifest_byte_length"],
"coordinator embedded snapshot manifest byte length",
)
dependency_file_count = _integer(
provenance["python_dependency_bundle_file_count"],
"coordinator Python dependency bundle file count",
)
dependency_bytes = _integer(
provenance["python_dependency_bundle_byte_length"],
"coordinator Python dependency bundle byte length",
)
dependency_manifest_bytes = _integer(
provenance["python_dependency_bundle_manifest_byte_length"],
"coordinator Python dependency bundle manifest byte length",
)
size_bytes = _integer(image["size_bytes"], "coordinator image size")
layer_bytes = _integer(image["thin_layer_bytes"], "coordinator thin layer size")
maximum_layer_bytes = _integer(
@@ -1111,6 +1135,8 @@ def _load_installation_evidence(
"git_archive_sha256",
"staged_snapshot_sha256",
"embedded_snapshot_manifest_sha256",
"python_dependency_bundle_sha256",
"python_dependency_bundle_manifest_sha256",
):
_require_digest(
_string(provenance[key], f"coordinator {key}"),
@@ -1128,9 +1154,14 @@ def _load_installation_evidence(
or provenance["git_archive_verification"] != "external-before-extract"
or provenance["staged_snapshot_canonicalization"]
!= "utf8-path-nul-length-nul-sha256-lf-v1"
or provenance["python_dependency_bundle_canonicalization"]
!= "utf8-path-nul-length-nul-sha256-lf-v1"
or file_count <= 0
or snapshot_bytes <= 0
or embedded_manifest_bytes <= 0
or dependency_file_count <= 0
or dependency_bytes <= 0
or dependency_manifest_bytes <= 0
or image["tag"]
!= f"ndc/mission-core-observatory-worker-agent:{source_revision[:12]}"
or image["id"] != f"sha256:{coordinator_image_sha256}"
@@ -1147,12 +1178,15 @@ def _load_installation_evidence(
)
is None
or runtime["workdir"] != "/opt/nodedc/mission-core"
or runtime["pythonpath"]
!= "/opt/nodedc/mission-core/src:/opt/nodedc/mission-core/deps"
or runtime["entrypoint"]
!= ["python3", "-m", "k1link.observatory.m49_worker_container_main"]
or runtime["command"] != []
or runtime["authority"] != "observation-only"
or runtime["models"] != "external"
or runtime["runtime_registries"] != "external-read-only"
or runtime["python_dependencies"] != "embedded-sealed-build-input"
or smoke
!= {
"network": "none",
@@ -1160,6 +1194,10 @@ def _load_installation_evidence(
"staged_source_bytes": "matched",
"embedded_context_bytes": "matched",
"embedded_snapshot_manifest": "matched",
"python_dependency_bundle_bytes": "matched",
"python_dependency_bundle_manifest": "matched",
"required_dependency_versions": "matched",
"offline_dependency_operations": "passed",
"result": "passed",
}
):
@@ -1,5 +1,5 @@
{
"schema_version": "missioncore.observatory-worker-agent-build-context/v1",
"schema_version": "missioncore.observatory-worker-agent-build-context/v2",
"artifact_id": "observatory-worker-006-agent",
"worker_id": "worker-006",
"source_contract": {
@@ -38,6 +38,27 @@
"image_path": "/opt/nodedc/mission-core/release/worker-006-agent-build-context.json"
}
],
"external_build_inputs": [
{
"role": "python-dependency-bundle",
"required": true,
"provenance_requirement": "already-proven Python dependency tree from the previously accepted Worker; build input only",
"source_path": null,
"image_path": "/opt/nodedc/mission-core/deps",
"manifest_image_path": "/opt/nodedc/mission-core/release/worker-006-agent-python-dependency-bundle.json",
"manifest_schema_version": "missioncore.observatory-worker-agent-python-dependency-bundle/v1",
"identity": {
"algorithm": "sha256",
"subject": "complete regular-file inventory",
"canonicalization": "utf8-path-nul-length-nul-sha256-lf-v1",
"path_order": "ordinal"
},
"included_in_git_archive": false,
"copied_into_image": true,
"runtime_bind_allowed": false,
"network_install_allowed": false
}
],
"embedded_configuration": [],
"external_runtime_files": [
{
@@ -58,7 +79,7 @@
}
],
"runtime": {
"pythonpath": "/opt/nodedc/mission-core/src",
"pythonpath": "/opt/nodedc/mission-core/src:/opt/nodedc/mission-core/deps",
"entrypoint": [
"python3",
"-m",
@@ -67,6 +88,8 @@
"composition_module": "k1link.observatory.m49_worker_service",
"configuration_baked_into_image": false,
"runtime_registries_baked_into_image": false,
"python_dependency_bundle_baked_into_image": true,
"python_dependency_bundle_runtime_bind_allowed": false,
"models_baked_into_image": false,
"executor_releases_baked_into_image": false
},
@@ -1,5 +1,5 @@
{
"schema_version": "missioncore.observatory-worker-agent-install-plan/v1",
"schema_version": "missioncore.observatory-worker-agent-install-plan/v2",
"state": "planned-not-built",
"artifact_id": "observatory-worker-006-agent",
"worker_id": "worker-006",
@@ -32,6 +32,27 @@
],
"embedded_manifest": "/opt/nodedc/mission-core/release/worker-006-agent-staged-snapshot.json"
},
"python_dependency_bundle": {
"state": "required-external-build-input",
"provenance_requirement": "already-proven Python dependency tree from the previously accepted Worker; build input only",
"source_root": null,
"expected_sha256": null,
"identity_subject": "complete regular-file inventory",
"canonicalization": "utf8-path-nul-length-nul-sha256-lf-v1",
"path_order": "ordinal",
"reject_reparse_points": true,
"reject_unexpected_non_regular_entries": true,
"verify_timing": [
"before temporary container creation",
"after dependency installation and before image commit"
],
"image_path": "/opt/nodedc/mission-core/deps",
"manifest_schema_version": "missioncore.observatory-worker-agent-python-dependency-bundle/v1",
"embedded_manifest": "/opt/nodedc/mission-core/release/worker-006-agent-python-dependency-bundle.json",
"included_in_git_archive": false,
"runtime_bind_allowed": false,
"network_install_allowed": false
},
"base_image": {
"reference": "nvcr.io/nvidia/tritonserver:26.06-py3@sha256:58df7489c3f2276f9591d500a012dee03e23d35543ce3c390b4c001e6bf90794",
"sha256": "58df7489c3f2276f9591d500a012dee03e23d35543ce3c390b4c001e6bf90794",
@@ -50,8 +71,10 @@
"maximum_thin_layer_bytes": 33554432,
"embedded_payload": [
"/opt/nodedc/mission-core/src/k1link",
"/opt/nodedc/mission-core/deps",
"/opt/nodedc/mission-core/release/worker-006-agent-build-context.json",
"/opt/nodedc/mission-core/release/worker-006-agent-staged-snapshot.json"
"/opt/nodedc/mission-core/release/worker-006-agent-staged-snapshot.json",
"/opt/nodedc/mission-core/release/worker-006-agent-python-dependency-bundle.json"
]
},
"required_preflight": [
@@ -61,7 +84,10 @@
"base image inspect ID equals the pinned SHA-256",
"context archive contains exactly the context manifest entries",
"git archive SHA-256 was verified externally before extraction",
"staged snapshot SHA-256 matches the exact canonical regular-file inventory"
"staged snapshot SHA-256 matches the exact canonical regular-file inventory",
"Python dependency bundle is an external build input with an exact expected SHA-256",
"Python dependency bundle SHA-256 matches its ordinal canonical regular-file inventory",
"Python dependency bundle contains the five exact smoke-tested package versions"
],
"image_tag_template": "ndc/mission-core-observatory-worker-agent:<source-revision-12>"
},
@@ -79,6 +105,11 @@
"com.nodedc.build-context.sha256": "<git-archive-sha256>",
"com.nodedc.staged-snapshot.sha256": "<staged-snapshot-sha256>",
"com.nodedc.embedded-snapshot-manifest.sha256": "<embedded-snapshot-manifest-sha256>",
"com.nodedc.python-dependency-bundle.sha256": "<python-dependency-bundle-sha256>",
"com.nodedc.python-dependency-bundle.file-count": "<python-dependency-bundle-file-count>",
"com.nodedc.python-dependency-bundle.byte-length": "<python-dependency-bundle-byte-length>",
"com.nodedc.python-dependency-bundle.manifest.sha256": "<python-dependency-bundle-manifest-sha256>",
"com.nodedc.python-dependency-bundle.manifest.byte-length": "<python-dependency-bundle-manifest-byte-length>",
"com.nodedc.build-method": "docker-commit-exact-layer-v1"
},
"rootfs": {
@@ -90,7 +121,9 @@
"embedded_identity": {
"source_tree": "byte-for-byte and bidirectional path match against staged src/k1link",
"context_manifest": "byte-for-byte match against the staged context manifest",
"snapshot_manifest": "byte-for-byte match against the generated manifest covering every staged file, including the Dockerfile"
"snapshot_manifest": "byte-for-byte match against the generated manifest covering every staged file, including the Dockerfile",
"python_dependency_bundle": "byte-for-byte and bidirectional path match against the mandatory external build input",
"python_dependency_bundle_manifest": "byte-for-byte match against the generated manifest covering every embedded dependency file"
},
"smoke": {
"network": "none",
@@ -104,6 +137,16 @@
"staged_source_bytes": "matched",
"embedded_context_bytes": "matched",
"embedded_snapshot_manifest": "matched",
"embedded_python_dependency_bundle": "matched",
"embedded_python_dependency_bundle_manifest": "matched",
"pythonpath": "/opt/nodedc/mission-core/src:/opt/nodedc/mission-core/deps",
"python_package_versions": {
"httpx": "0.28.1",
"lz4": "4.4.5",
"paho-mqtt": "2.1.0",
"PyYAML": "6.0.3",
"typing_extensions": "4.16.0"
},
"expected_result": "exit-0"
}
},
@@ -268,7 +311,10 @@
"external_assets": {
"model_images": "pre-existing exact local Docker images selected only by installed executor adapters",
"model_weights": "pre-existing exact local read-only assets selected only by installed executor adapters",
"python_dependency_bundle": "mandatory external build input copied into /opt/nodedc/mission-core/deps and never mounted at runtime",
"baked_into_agent_image": false,
"python_dependency_bundle_baked_into_agent_image": true,
"python_dependency_bundle_runtime_bind_allowed": false,
"queued_jobs_may_select_paths_or_commands": false
},
"lab_v1_runner_installation_input": {
@@ -289,7 +335,7 @@
]
},
"receipt_skeleton": {
"schema_version": "missioncore.observatory-worker-agent-image-installation/v1",
"schema_version": "missioncore.observatory-worker-agent-image-installation/v2",
"status": null,
"worker_id": "worker-006",
"build_method": "docker-commit-exact-layer-v1",
@@ -302,7 +348,13 @@
"staged_snapshot_byte_length": null,
"staged_snapshot_canonicalization": "utf8-path-nul-length-nul-sha256-lf-v1",
"embedded_snapshot_manifest_sha256": null,
"embedded_snapshot_manifest_byte_length": null
"embedded_snapshot_manifest_byte_length": null,
"python_dependency_bundle_sha256": null,
"python_dependency_bundle_file_count": null,
"python_dependency_bundle_byte_length": null,
"python_dependency_bundle_canonicalization": "utf8-path-nul-length-nul-sha256-lf-v1",
"python_dependency_bundle_manifest_sha256": null,
"python_dependency_bundle_manifest_byte_length": null
},
"base_image_sha256": "58df7489c3f2276f9591d500a012dee03e23d35543ce3c390b4c001e6bf90794",
"derived_image_sha256": null,
@@ -327,9 +379,11 @@
"k1link.observatory.m49_worker_container_main"
],
"command": [],
"pythonpath": "/opt/nodedc/mission-core/src:/opt/nodedc/mission-core/deps",
"authority": "observation-only",
"models": "external",
"runtime_registries": "external-read-only"
"runtime_registries": "external-read-only",
"python_dependencies": "embedded-sealed-build-input"
},
"smoke": {
"network": "none",
@@ -337,6 +391,10 @@
"staged_source_bytes": null,
"embedded_context_bytes": null,
"embedded_snapshot_manifest": null,
"python_dependency_bundle_bytes": null,
"python_dependency_bundle_manifest": null,
"required_dependency_versions": null,
"offline_dependency_operations": null,
"result": "not-run"
}
}