0x72dc7c30a672d1a7478545aa9721ceda889e91f7e4154617338b2d5b0331d6cfOverall status: verified.
Download provenance bundle (.tar)| MRTD | 0xb24d3b24e9e3c16012376b52362ca09856c4adecb709d5fac33addf1c47e193da075b125b6c364115771390a5461e217 |
|---|---|
| RTMR0 | 0x90550e56509b94f99f4670a563e0dd0a2fa79b6d7b97fd52d051069d1b33d270b1858120034a43dac4f8daf509f2aeda |
| RTMR1 | 0x07e6f51aa763abfe75c3ddfbf4f425fe3f0ceff66d807a75e049303dce9addf68e7218729bd419638af63a370f65878c |
| RTMR2 | 0xf1c82667a354194467cd8419efd14a714560dd9b85b4c13b25c11e44bf4e126248c2255fad58c303fb0ca2921765d53a |
| RTMR3 | 0x3598be1aba8a82b8dcffeb9095184d7fac87311e4b8e599382ea3f6e2198168f59c2ad44550b266ef998e71632e18bac |
| MRCONFIGID | 0x019dbf79e75ef4218f8355a31c5af7198ebe7fe4268230b18d3909604fb699592b000000000000000000000000000000 |
| XFAM | 0xe702060000000000 |
| TD attributes | 0x0000001000000000 |
These exact files are inputs to the TDX measurement calculation for this workload.
cdi-phala-app-compose.json{"allowed_envs":["MOAI_GCS_SERVICE_ACCOUNT_JSON_B64","DSTACK_DOCKER_USERNAME","DSTACK_DOCKER_PASSWORD","HF_TOKEN","PAYMENT_ADDRESS"],"docker_compose_file":"name: ritual-prod-shared-proxy\n\n# Production shared inference appliance for one 8xH200 Phala CVM.\n# Chain-agnostic by design: chains attach later through the proxy /register API.\n# Required encrypted deployment environment:\n# HF_TOKEN\n# MOAI_GCS_SERVICE_ACCOUNT_JSON_B64\n\nservices:\n # Fetch immutable model revisions into the app-scoped persistent cache.\n model-bootstrap:\n image: docker.io/ritualnetwork/attested-sglang@sha256:636477429594b690d83a0bb086b04c52086390c63be78141918e356b04ae904e\n restart: \"no\"\n volumes:\n - hf-model-cache:/root/.cache/huggingface\n secrets:\n - hf-token\n environment:\n HF_HOME: /root/.cache/huggingface\n entrypoint: [\"/bin/bash\", \"-ceu\"]\n command:\n - |\n python3 - <<'PY'\n from huggingface_hub import snapshot_download\n from pathlib import Path\n\n token = Path(\"/run/secrets/hf-token\").read_text().strip()\n if not token:\n raise RuntimeError(\"HF token secret is empty\")\n\n snapshots = (\n (\"deepseek-ai/DeepSeek-V4-Flash-0731\", \"7872f01b1d1fe23eabc4c98b48bffcef5a386062\"),\n (\"black-forest-labs/FLUX.2-klein-4B\", \"e7b7dc27f91deacad38e78976d1f2b499d76a294\"),\n (\"Wan-AI/Wan2.2-T2V-A14B-Diffusers\", \"5be7df9619b54f4e2667b2755bc6a756675b5cd7\"),\n )\n for repo_id, revision in snapshots:\n snapshot_download(repo_id=repo_id, revision=revision, token=token)\n PY\n\n dynamo-etcd:\n restart: unless-stopped\n logging:\n driver: json-file\n options:\n max-size: \"100m\"\n max-file: \"5\"\n image: docker.io/ritualnetwork/attested-etcd@sha256:4c15df3a62f8ffb25007194b09ab89731bd8ae4cc98a5cccb76bceff8d257232\n network_mode: host\n command:\n - etcd\n - --advertise-client-urls=http://127.0.0.1:2379\n - --listen-client-urls=http://127.0.0.1:2379\n - --data-dir=/etcd-data\n volumes:\n - dynamo-etcd:/etcd-data\n healthcheck:\n test: [\"CMD\", \"etcdctl\", \"--endpoints=http://127.0.0.1:2379\", \"endpoint\", \"health\"]\n interval: 10s\n timeout: 5s\n retries: 12\n\n dynamo-nats:\n restart: unless-stopped\n logging:\n driver: json-file\n options:\n max-size: \"100m\"\n max-file: \"5\"\n image: docker.io/ritualnetwork/attested-nats@sha256:0275c31c7b0100817abd03a10dc519697f0fdc710de8fa8c5c7f7ad41607e542\n network_mode: host\n configs:\n - source: dynamo-nats-config\n target: /etc/nats/nats-server.conf\n command: [\"--config\", \"/etc/nats/nats-server.conf\"]\n healthcheck:\n test: [\"CMD-SHELL\", \"wget -q -O /dev/null 'http://127.0.0.1:8222/healthz?js-enabled-only=true'\"]\n interval: 10s\n timeout: 5s\n retries: 12\n start_period: 10s\n\n dynamo-frontend:\n restart: unless-stopped\n logging:\n driver: json-file\n options:\n max-size: \"100m\"\n max-file: \"5\"\n image: docker.io/ritualnetwork/attested-dynamo-sglang@sha256:f769e1278140b2a396cb1248be0802d4b2360fef4f3ca0b6cf4acf2edcf132ef\n user: \"0:0\"\n working_dir: /workspace\n network_mode: host\n depends_on:\n dynamo-etcd:\n condition: service_healthy\n dynamo-nats:\n condition: service_healthy\n model-bootstrap:\n condition: service_completed_successfully\n volumes:\n - hf-model-cache:/root/.cache/huggingface\n environment:\n HF_HOME: /root/.cache/huggingface\n HF_HUB_OFFLINE: \"1\"\n ETCD_ENDPOINTS: http://127.0.0.1:2379\n NATS_SERVER: nats://127.0.0.1:4222\n DYN_HTTP_PORT: \"30010\"\n OTEL_SERVICE_NAME: dynamo-frontend\n command:\n - python3\n - -m\n - dynamo.frontend\n - --http-host\n - 127.0.0.1\n - --http-port\n - \"30010\"\n - --router-mode\n - round-robin\n - --request-plane\n - tcp\n - --dyn-chat-processor\n - sglang\n healthcheck:\n test: [\"CMD-SHELL\", \"curl -sf http://127.0.0.1:30010/v1/models >/dev/null\"]\n interval: 15s\n timeout: 5s\n retries: 120\n start_period: 30s\n\n # DeepSeek text plane: host GPUs 0-3.\n dynamo-worker:\n restart: unless-stopped\n logging:\n driver: json-file\n options:\n max-size: \"100m\"\n max-file: \"5\"\n image: docker.io/ritualnetwork/attested-dynamo-sglang@sha256:f769e1278140b2a396cb1248be0802d4b2360fef4f3ca0b6cf4acf2edcf132ef\n user: \"0:0\"\n working_dir: /workspace\n network_mode: host\n ipc: host\n depends_on:\n dynamo-frontend:\n condition: service_started\n model-bootstrap:\n condition: service_completed_successfully\n volumes:\n - hf-model-cache:/root/.cache/huggingface\n - sglang-cache:/root/.cache/sglang\n - deep-gemm-cache:/root/.cache/deep_gemm\n - flashinfer-cache:/root/.cache/flashinfer\n environment:\n HF_HOME: /root/.cache/huggingface\n HF_HUB_OFFLINE: \"1\"\n PYTORCH_CUDA_ALLOC_CONF: expandable_segments:True\n SGLANG_JIT_DEEPGEMM_PRECOMPILE: \"0\"\n SGLANG_JIT_DEEPGEMM_FAST_WARMUP: \"1\"\n NCCL_CUMEM_ENABLE: \"1\"\n ETCD_ENDPOINTS: http://127.0.0.1:2379\n NATS_SERVER: nats://127.0.0.1:4222\n DYN_SYSTEM_PORT: \"8081\"\n OTEL_SERVICE_NAME: dynamo-worker\n deploy:\n resources:\n reservations:\n devices:\n - driver: nvidia\n device_ids: [\"0\", \"1\", \"2\", \"3\"]\n capabilities: [gpu]\n ulimits:\n memlock: -1\n stack: 67108864\n nofile:\n soft: 65536\n hard: 65536\n cap_add: [SYS_PTRACE]\n command:\n - python3\n - -m\n - dynamo.sglang\n - --trust-remote-code\n - --model-path\n - /root/.cache/huggingface/hub/models--deepseek-ai--DeepSeek-V4-Flash-0731/snapshots/7872f01b1d1fe23eabc4c98b48bffcef5a386062\n - --served-model-name\n - deepseek-ai/DeepSeek-V4-Flash-0731\n - --tp\n - \"4\"\n - --moe-runner-backend\n - marlin\n - --speculative-algorithm\n - DSPARK\n - --mem-fraction-static\n - \"0.88\"\n - --context-length\n - \"1048576\"\n - --max-running-requests\n - \"16\"\n - --incremental-streaming-output\n - --dyn-reasoning-parser\n - deepseek-v4\n - --dyn-tool-call-parser\n - deepseekv4\n - --enable-metrics\n - --enable-cache-report\n - --host\n - 127.0.0.1\n healthcheck:\n test: [\"CMD-SHELL\", \"curl -sf http://127.0.0.1:8081/metrics >/dev/null\"]\n interval: 30s\n timeout: 10s\n retries: 10\n start_period: 45m\n\n # Wan video plane: host GPUs 4-5.\n wan-t2v:\n restart: unless-stopped\n logging:\n driver: json-file\n options:\n max-size: \"100m\"\n max-file: \"5\"\n image: docker.io/ritualnetwork/attested-sglang-diffusion@sha256:4a4e3223abcb7f7323868be64ac00b7091ac87cbb052622c40e6c341419e4cff\n network_mode: host\n ipc: host\n shm_size: \"128g\"\n depends_on:\n model-bootstrap:\n condition: service_completed_successfully\n volumes:\n - hf-model-cache:/root/.cache/huggingface\n - wan-video-outputs:/outputs\n environment:\n HF_HOME: /root/.cache/huggingface\n HF_HUB_OFFLINE: \"1\"\n SGLANG_CACHE_DIT_ENABLED: \"true\"\n SGLANG_CACHE_DIT_TAYLORSEER: \"true\"\n SGLANG_CACHE_DIT_TS_ORDER: \"2\"\n deploy:\n resources:\n reservations:\n devices:\n - driver: nvidia\n device_ids: [\"4\", \"5\"]\n capabilities: [gpu]\n command:\n - sglang\n - serve\n - --model-path\n - /root/.cache/huggingface/hub/models--Wan-AI--Wan2.2-T2V-A14B-Diffusers/snapshots/5be7df9619b54f4e2667b2755bc6a756675b5cd7\n - --host\n - 127.0.0.1\n - --port\n - \"30002\"\n # Diffusion services otherwise share fixed defaults (master 30005,\n # scheduler 5555) even when their HTTP ports differ.\n - --master-port\n - \"31000\"\n - --scheduler-port\n - \"31100\"\n - --num-gpus\n - \"2\"\n - --tp-size\n - \"1\"\n - --sp-degree\n - \"2\"\n - --ulysses-degree\n - \"2\"\n - --ring-degree\n - \"1\"\n - --attention-backend\n - fa\n - --dit-cpu-offload\n - \"false\"\n - --dit-layerwise-offload\n - \"false\"\n - --text-encoder-cpu-offload\n - \"false\"\n - --image-encoder-cpu-offload\n - \"false\"\n - --vae-cpu-offload\n - \"false\"\n - --output-path\n - /outputs\n healthcheck:\n test:\n - CMD\n - python3\n - -c\n - \"import urllib.request; urllib.request.urlopen('http://127.0.0.1:30002/health', timeout=10).read()\"\n interval: 30s\n timeout: 15s\n retries: 10\n start_period: 30m\n\n # FLUX image plane: host GPU 6.\n flux2-klein:\n restart: unless-stopped\n logging:\n driver: json-file\n options:\n max-size: \"100m\"\n max-file: \"5\"\n image: docker.io/ritualnetwork/attested-sglang-diffusion@sha256:4a4e3223abcb7f7323868be64ac00b7091ac87cbb052622c40e6c341419e4cff\n network_mode: host\n ipc: host\n depends_on:\n model-bootstrap:\n condition: service_completed_successfully\n volumes:\n - hf-model-cache:/root/.cache/huggingface\n - flux-image-outputs:/outputs\n environment:\n HF_HOME: /root/.cache/huggingface\n HF_HUB_OFFLINE: \"1\"\n SGLANG_CACHE_DIT_ENABLED: \"true\"\n # device_ids exposes host GPU 6 as GPU 0 inside this container.\n CUDA_VISIBLE_DEVICES: \"0\"\n deploy:\n resources:\n reservations:\n devices:\n - driver: nvidia\n device_ids: [\"6\"]\n capabilities: [gpu]\n command:\n - sglang\n - serve\n - --model-path\n - /root/.cache/huggingface/hub/models--black-forest-labs--FLUX.2-klein-4B/snapshots/e7b7dc27f91deacad38e78976d1f2b499d76a294\n - --host\n - 127.0.0.1\n - --port\n - \"30003\"\n # Keep diffusion control planes disjoint from Wan and each other.\n - --master-port\n - \"32000\"\n - --scheduler-port\n - \"32100\"\n - --output-path\n - /outputs\n healthcheck:\n test:\n - CMD\n - python3\n - -c\n - \"import urllib.request; urllib.request.urlopen('http://127.0.0.1:30003/health', timeout=10).read()\"\n interval: 30s\n timeout: 15s\n retries: 10\n start_period: 15m\n\n # Audio shares host GPU 6 with FLUX, matching the current qualified topology.\n rai-audio:\n restart: unless-stopped\n logging:\n driver: json-file\n options:\n max-size: \"100m\"\n max-file: \"5\"\n image: docker.io/ritualnetwork/rai-simple@sha256:d0269af97a4d722a48647d723e7aff8a5bddcd1977b64347c14d162c35cfc7f0\n network_mode: host\n environment:\n RAI_PORT: \"30004\"\n RAI_HOST: 127.0.0.1\n RAI_WORKERS: \"1\"\n RAI_MODEL: LiquidAI/LFM2.5-Audio-1.5B\n RAI_DEVICE: cuda\n RAI_DTYPE: bfloat16\n # device_ids exposes host GPU 6 as GPU 0 inside this container.\n CUDA_VISIBLE_DEVICES: \"0\"\n TORCH_COMPILE_DISABLE: \"1\"\n TORCHDYNAMO_DISABLE: \"1\"\n deploy:\n resources:\n reservations:\n devices:\n - driver: nvidia\n device_ids: [\"6\"]\n capabilities: [gpu]\n command: [\"python3\", \"-m\", \"rai.simple_server\"]\n healthcheck:\n test: [\"CMD-SHELL\", \"curl -sf http://127.0.0.1:30004/health >/dev/null\"]\n interval: 15s\n timeout: 5s\n retries: 20\n start_period: 120s\n\n # MOAI Full-E2E-only FHE plane: host GPU 7. The client secret key never enters GCS.\n moai-fhe:\n restart: unless-stopped\n logging:\n driver: json-file\n options:\n max-size: \"100m\"\n max-file: \"5\"\n image: docker.io/ritualnetwork/ritual-moai-gpu@sha256:2f6e0751cf2383cd67cc1510adcd70699bba402d7d6a8ee285e08f438ace2245\n network_mode: host\n environment:\n MOAI_NUM_LAYERS: \"12\"\n MOAI_HIDDEN_SIZE: \"768\"\n MOAI_NUM_HEADS: \"12\"\n MOAI_HEAD_SIZE: \"64\"\n MOAI_INTERMEDIATE_SIZE: \"3072\"\n MOAI_MAX_SEQ_LENGTH: \"128\"\n MOAI_BATCH_SIZE: \"256\"\n MOAI_MULT_DEPTH: \"29\"\n BERT_BINARY_PATH: /app/build/fhe_b_inference_server\n BERT_WEIGHTS_DIR: /app/build\n MOAI_HTTP_HOST: 127.0.0.1\n MOAI_HTTP_PORT: \"30008\"\n MOAI_GRPC_HOST: 127.0.0.1\n MOAI_GRPC_PORT: \"30009\"\n MOAI_MODEL_NAME: bert-base-uncased\n MOAI_MAX_CONCURRENT_INFERENCE: \"1\"\n GCS_BUCKET: ritual-moai-fhe-pt1-e2e\n MOAI_GCS_CACHE: \"1\"\n MOAI_GCS_CACHE_DIR: /app/gcs_cache\n OMP_NUM_THREADS: \"8\"\n PYTHONUNBUFFERED: \"1\"\n # device_ids exposes host GPU 7 as GPU 0 inside this container.\n CUDA_VISIBLE_DEVICES: \"0\"\n deploy:\n resources:\n reservations:\n devices:\n - driver: nvidia\n device_ids: [\"7\"]\n capabilities: [gpu]\n volumes:\n - moai-keys:/app/keys\n - moai-logs:/app/logs\n - moai-gcs-cache:/app/gcs_cache\n tmpfs:\n - /run/moai-secrets:rw,noexec,nosuid,nodev,mode=0700,size=1m\n secrets:\n - moai-gcs-sa-b64\n entrypoint: [\"/bin/bash\", \"-ceu\"]\n command:\n - |\n umask 077\n credential=/run/moai-secrets/gcs-service-account.json\n child_pid=\n cleanup() { rm -f \"$${credential}\"; }\n terminate() {\n trap - HUP INT TERM\n if [ -n \"$${child_pid}\" ]; then\n kill -TERM \"$${child_pid}\" 2>/dev/null || true\n wait \"$${child_pid}\" 2>/dev/null || true\n fi\n exit 143\n }\n trap cleanup EXIT\n trap terminate HUP INT TERM\n base64 -d /run/secrets/moai-gcs-sa-b64 >\"$${credential}\"\n chmod 0600 \"$${credential}\"\n export GOOGLE_APPLICATION_CREDENTIALS=\"$${credential}\"\n python3 /app/python/server.py &\n child_pid=$$!\n wait \"$${child_pid}\"\n healthcheck:\n test:\n - CMD\n - python3\n - -c\n - \"import urllib.request; urllib.request.urlopen('http://127.0.0.1:30008/health', timeout=5).read()\"\n interval: 30s\n timeout: 10s\n retries: 20\n start_period: 180s\n\n redis:\n restart: unless-stopped\n logging:\n driver: json-file\n options:\n max-size: \"100m\"\n max-file: \"5\"\n image: docker.io/ritualnetwork/attested-redis@sha256:ab7cc60b5a997c5df4241a7de2508af1a05d01ee2a7506565928af44263d8c56\n network_mode: host\n command:\n - redis-server\n - --maxmemory\n - 1gb\n - --maxmemory-policy\n - allkeys-lru\n - --bind\n - 127.0.0.1\n - --protected-mode\n - \"yes\"\n - --save\n - \"\"\n - --appendonly\n - \"no\"\n healthcheck:\n test: [\"CMD-SHELL\", \"redis-cli ping | grep -q PONG\"]\n interval: 10s\n timeout: 5s\n retries: 12\n\n bifrost:\n restart: unless-stopped\n logging:\n driver: json-file\n options:\n max-size: \"100m\"\n max-file: \"5\"\n image: docker.io/ritualnetwork/attested-bifrost@sha256:99687dd5b49bed19aff7b37f0ec22b0e145da9cb17e0096b415b2b3d41e3893f\n network_mode: host\n environment:\n APP_HOST: 127.0.0.1\n volumes:\n - bifrost-data:/app/data\n configs:\n - source: bifrost-config\n target: /app/data/config.json\n healthcheck:\n test: [\"CMD\", \"wget\", \"--no-verbose\", \"--tries=1\", \"--spider\", \"http://127.0.0.1:8080/health\"]\n interval: 15s\n timeout: 5s\n retries: 12\n\n # Chain-agnostic attested front door. Chains register after deployment via /register.\n shared-proxy:\n restart: unless-stopped\n logging:\n driver: json-file\n options:\n max-size: \"100m\"\n max-file: \"5\"\n image: docker.io/ritualnetwork/ritual-vllm-proxy-go:cf17d76-93d86b2-amd64@sha256:3b7b49baba9bad656403f9636ff5eecc7c6f8b9c612639c46ea9433c3afee83f\n network_mode: host\n privileged: true\n depends_on:\n dynamo-frontend:\n condition: service_healthy\n dynamo-worker:\n condition: service_healthy\n wan-t2v:\n condition: service_healthy\n flux2-klein:\n condition: service_healthy\n bifrost:\n condition: service_healthy\n redis:\n condition: service_healthy\n rai-audio:\n condition: service_healthy\n moai-fhe:\n condition: service_healthy\n devices:\n - /dev/tdx_guest:/dev/tdx_guest\n - /dev/nvidia0:/dev/nvidia0\n - /dev/nvidia1:/dev/nvidia1\n - /dev/nvidia2:/dev/nvidia2\n - /dev/nvidia3:/dev/nvidia3\n - /dev/nvidia4:/dev/nvidia4\n - /dev/nvidia5:/dev/nvidia5\n - /dev/nvidia6:/dev/nvidia6\n - /dev/nvidia7:/dev/nvidia7\n - /dev/nvidiactl:/dev/nvidiactl\n - /dev/nvidia-uvm:/dev/nvidia-uvm\n deploy:\n resources:\n reservations:\n devices:\n - driver: nvidia\n count: all\n capabilities: [gpu, compute, utility]\n volumes:\n - /etc/tdx-attest.conf:/etc/tdx-attest.conf:ro\n - /var/run/dstack.sock:/var/run/dstack.sock\n - /usr/bin/nvidia-smi:/usr/bin/nvidia-smi:ro\n environment:\n PORT: \"8020\"\n OPS_PORT: \"8021\"\n LOG_JSON: \"true\"\n HTTP_REQUEST_LOGGING_ENABLED: \"false\"\n MODEL_NAME: deepseek-ai/DeepSeek-V4-Flash-0731\n VLLM_BASE_URL: http://127.0.0.1:30010\n LLM_ADMISSION_ENABLED: \"true\"\n LLM_QUEUE_DEPTH_LIMIT: \"100\"\n LLM_ADMISSION_POLL_INTERVAL_MS: \"2000\"\n LLM_ADMISSION_METRICS_URL: http://127.0.0.1:8081/metrics\n LLM_ADMISSION_METRIC_NAME: sglang:num_queue_reqs\n LLM_MAX_OUTPUT_TOKENS: \"8192\"\n LLM_DEFAULT_OUTPUT_TOKENS: \"4096\"\n LLM_TRACE_LOGGING_ENABLED: \"false\"\n LLM_TRACE_LOG_REQUEST_BODY: \"false\"\n LLM_TRACE_REQUEST_BODY_MAX_BYTES: \"4096\"\n IMAGE_BACKEND_URL: http://127.0.0.1:8080/openai\n AUDIO_BACKEND_URL: http://127.0.0.1:8080/openai\n VIDEO_BACKEND_URL: http://127.0.0.1:30002\n MOAI_BASE_URL: http://127.0.0.1:30008\n MOAI_TIMEOUT_SECONDS: \"600\"\n IMAGE_MODEL_NAME: black-forest-labs/FLUX.2-klein-4B\n AUDIO_MODEL_NAME: LiquidAI/LFM2.5-Audio-1.5B\n VIDEO_MODEL_NAME: Wan-AI/Wan2.2-T2V-A14B-Diffusers\n IMAGE_MAX_CONCURRENT: \"8\"\n IMAGE_MAX_QUEUED: \"20\"\n AUDIO_MAX_CONCURRENT: \"5\"\n AUDIO_MAX_QUEUED: \"10\"\n VIDEO_MAX_CONCURRENT: \"2\"\n VIDEO_MAX_QUEUED: \"4\"\n IMAGE_TIMEOUT_SECONDS: \"300\"\n AUDIO_TIMEOUT_SECONDS: \"300\"\n VIDEO_TIMEOUT_SECONDS: \"1800\"\n REDIS_HOST: 127.0.0.1\n REDIS_PORT: \"6379\"\n CHAT_CACHE_EXPIRATION: \"1200\"\n EXECUTOR_REGISTRY_CACHE_TTL: 3h\n TEE_TYPE: TDX\n MOCK_GPU_ATTESTATION: \"false\"\n MOCK_VLLM_MODE: \"false\"\n EVIDENCE_GETTER_PATH: /usr/local/bin/evidence_getter\n EVIDENCE_GETTER_USE_SUDO: \"false\"\n REGISTRATION_API_ENABLED: \"true\"\n REGISTRATION_ENABLED: \"false\"\n PAYMENT_ADDRESS: ${PAYMENT_ADDRESS:?PAYMENT_ADDRESS is required}\n SERVICE_ENDPOINT: https://${DSTACK_APP_ID:?DSTACK_APP_ID is required}-8020s.${DSTACK_GATEWAY_DOMAIN:?DSTACK_GATEWAY_DOMAIN is required}\n NVIDIA_VISIBLE_DEVICES: all\n NVIDIA_DRIVER_CAPABILITIES: compute,utility\n healthcheck:\n test: [\"CMD-SHELL\", \"curl -sf http://127.0.0.1:8021/health >/dev/null\"]\n interval: 15s\n timeout: 5s\n retries: 12\n start_period: 45s\n\n output-cleanup:\n restart: unless-stopped\n logging:\n driver: json-file\n options:\n max-size: \"100m\"\n max-file: \"5\"\n image: docker.io/ritualnetwork/attested-alpine@sha256:2296aa2ab950dd79c04a077af8b8d7de1c86f3c2402e6415e753be63b75b6dab\n volumes:\n - wan-video-outputs:/outputs/video\n - flux-image-outputs:/outputs/image\n environment:\n VIDEO_TTL_MIN: \"30\"\n IMAGE_TTL_MIN: \"15\"\n CLEANUP_INTERVAL_SEC: \"60\"\n entrypoint: [\"/bin/sh\", \"-ceu\"]\n command:\n - |\n while true; do\n find /outputs/video -type f -mmin +$${VIDEO_TTL_MIN} -delete 2>/dev/null || true\n find /outputs/image -type f -mmin +$${IMAGE_TTL_MIN} -delete 2>/dev/null || true\n sleep \"$${CLEANUP_INTERVAL_SEC}\"\n done\n\nconfigs:\n dynamo-nats-config:\n content: |\n host: \"127.0.0.1\"\n port: 4222\n http: \"127.0.0.1:8222\"\n jetstream {}\n bifrost-config:\n content: |\n {\n \"$$schema\": \"https://www.getbifrost.ai/schema\",\n \"providers\": {\n \"deepseek-ai\": {\n \"keys\": [{\n \"name\": \"deepseek-ai-dynamo-local\",\n \"value\": \"not-needed\",\n \"models\": [\"DeepSeek-V4-Flash-0731\", \"deepseek-ai/DeepSeek-V4-Flash-0731\"],\n \"weight\": 1\n }],\n \"network_config\": {\n \"base_url\": \"http://127.0.0.1:30010\",\n \"default_request_timeout_in_seconds\": 120,\n \"max_retries\": 3\n },\n \"custom_provider_config\": {\n \"is_key_less\": true,\n \"base_provider_type\": \"openai\"\n }\n },\n \"flux\": {\n \"keys\": [{\n \"name\": \"flux-sglang-local\",\n \"value\": \"not-needed\",\n \"models\": [\"black-forest-labs/FLUX.2-klein-4B\"],\n \"weight\": 1\n }],\n \"network_config\": {\n \"base_url\": \"http://127.0.0.1:30003\",\n \"default_request_timeout_in_seconds\": 300,\n \"max_retries\": 3\n },\n \"custom_provider_config\": {\n \"is_key_less\": true,\n \"base_provider_type\": \"openai\"\n }\n },\n \"audio\": {\n \"keys\": [{\n \"name\": \"audio-rai-local\",\n \"value\": \"not-needed\",\n \"models\": [\"LiquidAI/LFM2.5-Audio-1.5B\"],\n \"weight\": 1\n }],\n \"network_config\": {\n \"base_url\": \"http://127.0.0.1:30004\",\n \"default_request_timeout_in_seconds\": 300,\n \"max_retries\": 3\n },\n \"custom_provider_config\": {\n \"is_key_less\": true,\n \"base_provider_type\": \"openai\"\n }\n },\n \"video\": {\n \"keys\": [{\n \"name\": \"video-sglang-local\",\n \"value\": \"not-needed\",\n \"models\": [\"Wan-AI/Wan2.2-T2V-A14B-Diffusers\"],\n \"weight\": 1\n }],\n \"network_config\": {\n \"base_url\": \"http://127.0.0.1:30002\",\n \"default_request_timeout_in_seconds\": 1800,\n \"max_retries\": 1\n },\n \"custom_provider_config\": {\n \"is_key_less\": true,\n \"base_provider_type\": \"openai\"\n }\n }\n },\n \"config_store\": {\n \"enabled\": true,\n \"type\": \"sqlite\",\n \"config\": {\"path\": \"/app/data/config.db\"}\n },\n \"logs_store\": {\n \"enabled\": true,\n \"type\": \"sqlite\",\n \"config\": {\"path\": \"/app/data/logs.db\"}\n },\n \"client\": {\n \"initial_pool_size\": 300,\n \"allowed_origins\": [],\n \"enable_logging\": true,\n \"enable_governance\": false,\n \"allow_direct_keys\": false,\n \"max_request_body_size_mb\": 100\n }\n }\n\nsecrets:\n # Values come from Phala's encrypted deployment env and are mounted as files,\n # not exposed in long-lived container environments or process arguments.\n hf-token:\n environment: HF_TOKEN\n moai-gcs-sa-b64:\n environment: MOAI_GCS_SERVICE_ACCOUNT_JSON_B64\n\nvolumes:\n hf-model-cache:\n dynamo-etcd:\n sglang-cache:\n deep-gemm-cache:\n flashinfer-cache:\n wan-video-outputs:\n flux-image-outputs:\n bifrost-data:\n moai-keys:\n moai-logs:\n moai-gcs-cache:\n","features":["kms","tproxy-net"],"gateway_enabled":true,"kms_enabled":true,"local_key_provider_enabled":false,"manifest_version":2,"name":"app_53b1afccdae26112c17e890b6c3586cfae7717ce","no_instance_id":false,"port_policy":{"ports":[{"port":8020,"pp":false},{"port":8021,"pp":false},{"port":8090,"pp":false}],"restrict_mode":true},"pre_launch_script":"#!/bin/bash\necho \"----------------------------------------------\"\necho \"Running Phala Cloud Pre-Launch Script v0.0.19\"\necho \"----------------------------------------------\"\nset -e\n\n# Function: notify host\n\nnotify_host() {\n if command -v dstack-util >/dev/null 2>&1; then\n dstack-util notify-host -e \"$1\" -d \"$2\"\n else\n tdxctl notify-host -e \"$1\" -d \"$2\"\n fi\n}\n\nnotify_host_hoot_info() {\n notify_host \"boot.progress\" \"$1\"\n}\n\nnotify_host_hoot_error() {\n notify_host \"boot.error\" \"$1\"\n}\n\n# Function: Perform Docker cleanup\nperform_cleanup() {\n echo \"Pruning unused images\"\n docker image prune -af\n echo \"Pruning unused volumes\"\n docker volume prune -f\n notify_host_hoot_info \"docker cleanup completed\"\n}\n\n# Function: Check Docker login status without exposing credentials\ncheck_docker_login() {\n local registry=\"$1\"\n\n # When registry is specified, check auth entry for that registry in Docker config\n if [[ -n \"$registry\" ]]; then\n local docker_config_path=\"${DOCKER_CONFIG:-$HOME/.docker}/config.json\"\n if [[ -f \"$docker_config_path\" ]] && grep -q \"$registry\" \"$docker_config_path\"; then\n return 0\n else\n return 1\n fi\n fi\n\n # Fallback check when no explicit registry is provided\n if docker info 2>/dev/null | grep -q \"Username\"; then\n return 0\n else\n return 1\n fi\n}\n\n# Function: print the SHA256 fingerprint of every authorized key\n#\n# Output matches `ssh-keygen -lf` and the fingerprints GitHub and Phala Cloud\n# display, so an operator can match the boot log against the account's key list.\n# The guest image ships neither ssh-keygen nor a base64 applet (BusyBox has\n# base32 only), so openssl does both the decode and the digest.\nprint_authorized_key_fingerprints() {\n local file=\"$1\"\n if ! command -v openssl >/dev/null 2>&1; then\n echo \"openssl not available; skipping SSH key fingerprints\"\n return 0\n fi\n\n local key_type blob comment decoded_bytes fingerprint\n # `|| [[ -n \"$key_type\" ]]` keeps the final line when the file does not end\n # with a newline; read returns non-zero there but still fills the variables.\n while read -r key_type blob comment || [[ -n \"$key_type\" ]]; do\n if [[ -z \"$blob\" ]]; then\n continue\n fi\n # openssl exits 0 on undecodable input and emits nothing, which would\n # otherwise print the SHA256 of the empty string as a real fingerprint.\n decoded_bytes=$(printf '%s' \"$blob\" | openssl base64 -d -A 2>/dev/null | wc -c || true)\n if [[ \"$decoded_bytes\" -eq 0 ]]; then\n echo \" $key_type <unreadable key>\"\n continue\n fi\n fingerprint=$(\n printf '%s' \"$blob\" | openssl base64 -d -A 2>/dev/null | openssl dgst -sha256 -binary 2>/dev/null | openssl base64 -A 2>/dev/null | tr -d '=' || true\n )\n echo \" $key_type SHA256:$fingerprint\"\n done < \"$file\"\n}\n\n# Main logic starts here\necho \"Starting login process...\"\n\n# Check if Docker credentials exist\nif [[ -n \"$DSTACK_DOCKER_USERNAME\" && -n \"$DSTACK_DOCKER_PASSWORD\" ]]; then\n echo \"Docker credentials found\"\n DOCKER_REGISTRY_TARGET=\"${DSTACK_DOCKER_REGISTRY:-docker.io}\"\n echo \"Target Docker registry: $DOCKER_REGISTRY_TARGET\"\n\n # Check if already logged in\n if check_docker_login \"$DSTACK_DOCKER_REGISTRY\"; then\n echo \"Already logged in to Docker registry: $DOCKER_REGISTRY_TARGET\"\n else\n echo \"Logging in to Docker registry: $DOCKER_REGISTRY_TARGET\"\n # Login without exposing password in process list\n if [[ -n \"$DSTACK_DOCKER_REGISTRY\" ]]; then\n if ! echo \"$DSTACK_DOCKER_PASSWORD\" | docker login -u \"$DSTACK_DOCKER_USERNAME\" --password-stdin \"$DSTACK_DOCKER_REGISTRY\"; then\n echo \"Docker login failed: $DOCKER_REGISTRY_TARGET\"\n notify_host_hoot_error \"docker login failed\"\n exit 1\n fi\n elif ! echo \"$DSTACK_DOCKER_PASSWORD\" | docker login -u \"$DSTACK_DOCKER_USERNAME\" --password-stdin; then\n echo \"Docker login failed: $DOCKER_REGISTRY_TARGET\"\n notify_host_hoot_error \"docker login failed\"\n exit 1\n fi\n echo \"Docker login successful: $DOCKER_REGISTRY_TARGET\"\n fi\n# Check if AWS ECR credentials exist\nelif [[ -n \"$DSTACK_AWS_ACCESS_KEY_ID\" && -n \"$DSTACK_AWS_SECRET_ACCESS_KEY\" && -n \"$DSTACK_AWS_REGION\" && -n \"$DSTACK_AWS_ECR_REGISTRY\" ]]; then\n echo \"AWS ECR credentials found\"\n\n # Check if AWS CLI is installed\n if [ ! -f \"./aws/dist/aws\" ]; then\n notify_host_hoot_info \"awscli not installed, installing...\"\n echo \"AWS CLI not installed, installing...\"\n if ! curl \"https://awscli.amazonaws.com/awscli-exe-linux-x86_64-2.24.14.zip\" -o \"awscliv2.zip\"; then\n echo \"AWS CLI download failed\"\n notify_host_hoot_error \"awscli install failed\"\n exit 1\n fi\n if ! echo \"6ff031a26df7daebbfa3ccddc9af1450 awscliv2.zip\" | md5sum -c; then\n echo \"MD5 checksum failed\"\n notify_host_hoot_error \"awscli install failed\"\n exit 1\n fi\n unzip awscliv2.zip &> /dev/null\n else\n echo \"AWS CLI is already installed: ./aws/dist/aws\"\n fi\n\n # Set AWS credentials as environment variables\n export AWS_ACCESS_KEY_ID=\"$DSTACK_AWS_ACCESS_KEY_ID\"\n export AWS_SECRET_ACCESS_KEY=\"$DSTACK_AWS_SECRET_ACCESS_KEY\"\n export AWS_DEFAULT_REGION=\"$DSTACK_AWS_REGION\"\n\n # Set session token if provided (for temporary credentials)\n if [[ -n \"$DSTACK_AWS_SESSION_TOKEN\" ]]; then\n echo \"AWS session token found, using temporary credentials\"\n export AWS_SESSION_TOKEN=\"$DSTACK_AWS_SESSION_TOKEN\"\n fi\n\n # Test AWS credentials before attempting ECR login\n echo \"Testing AWS credentials...\"\n if ! ./aws/dist/aws sts get-caller-identity &> /dev/null; then\n echo \"AWS credentials test failed\"\n # For session token credentials, this might be expected if they're expired\n # Log warning but don't fail startup\n if [[ -n \"$DSTACK_AWS_SESSION_TOKEN\" ]]; then\n echo \"Warning: AWS temporary credentials may have expired, continuing startup\"\n notify_host_hoot_info \"AWS temporary credentials may have expired\"\n else\n echo \"AWS credentials test failed\"\n notify_host_hoot_error \"Invalid AWS credentials\"\n exit 1\n fi\n else\n echo \"Logging in to AWS ECR...\"\n if ./aws/dist/aws ecr get-login-password --region \"$DSTACK_AWS_REGION\" | docker login --username AWS --password-stdin \"$DSTACK_AWS_ECR_REGISTRY\"; then\n echo \"AWS ECR login successful\"\n notify_host_hoot_info \"AWS ECR login successful\"\n else\n echo \"AWS ECR login failed\"\n # For session token credentials, don't fail startup if login fails\n if [[ -n \"$DSTACK_AWS_SESSION_TOKEN\" ]]; then\n echo \"Warning: AWS ECR login failed with temporary credentials, continuing startup\"\n notify_host_hoot_info \"AWS ECR login failed with temporary credentials\"\n else\n notify_host_hoot_error \"AWS ECR login failed\"\n exit 1\n fi\n fi\n fi\nfi\n\nperform_cleanup\n\n#\n# GHCR image pull access verification (pure HTTP, no docker daemon)\n#\nif [[ \"$DOCKER_REGISTRY_TARGET\" == \"ghcr.io\" && -n \"$DSTACK_DOCKER_USERNAME\" && -n \"$DSTACK_DOCKER_PASSWORD\" ]]; then\n COMPOSE_IMAGES=$(grep 'image:' /dstack/docker-compose.yaml 2>/dev/null | awk '{print $2}' | tr -d '\"'\"'\" || true)\n HEADER=\"Accept: application/vnd.oci.image.index.v1+json,application/vnd.oci.image.manifest.v1+json,application/vnd.docker.distribution.manifest.list.v2+json,application/vnd.docker.distribution.manifest.v2+json\"\n for img in $COMPOSE_IMAGES; do\n [[ \"$img\" != ghcr.io/* ]] && continue\n ref=\"${img#ghcr.io/}\"\n # Digest-pinned refs (repo@sha256:...) use the digest as the manifest\n # reference; tag refs (repo:tag) use the tag, defaulting to latest.\n if [[ \"$ref\" == *@* ]]; then\n repo=\"${ref%%@*}\"\n reference=\"${ref#*@}\"\n else\n repo=\"${ref%%:*}\"\n reference=\"${ref##*:}\"\n [[ \"$reference\" == \"$ref\" ]] && reference=\"latest\"\n fi\n echo \"Verifying GHCR pull access: $img\"\n token=$(curl -sf -u \"$DSTACK_DOCKER_USERNAME:$DSTACK_DOCKER_PASSWORD\" \"https://ghcr.io/token?service=ghcr.io&scope=repository:${repo}:pull\" | jq -r '.token // empty' || true)\n if [[ -z \"$token\" ]]; then\n echo \"ERROR: GHCR token exchange failed for $img\"\n notify_host_hoot_error \"GHCR token exchange failed: $img\"\n exit 1\n fi\n http_code=$(curl -s -o /dev/null -w \"%{http_code}\" -H \"Authorization: Bearer $token\" -H \"$HEADER\" \"https://ghcr.io/v2/${repo}/manifests/${reference}\")\n if [[ \"$http_code\" != \"200\" ]]; then\n echo \"ERROR: GHCR pull access denied for $img (HTTP $http_code)\"\n notify_host_hoot_error \"GHCR pull access denied: $img (HTTP $http_code)\"\n exit 1\n fi\n echo \"GHCR pull access OK: $img\"\n done\nfi\n\n#\n# Pull latest images from docker-compose.yaml so existing CVMs pick up new tags.\n# Pull is fail-soft: short-lived tokens may expire between login and pull, but\n# falling back to already-cached images is preferable to blocking boot.\n#\necho \"Images before pull:\"\ndocker images --format '{{.Repository}}:{{.Tag}} {{.ID}} ({{.CreatedSince}})'\n\necho \"Pulling latest images from /dstack/docker-compose.yaml...\"\nif docker compose -f /dstack/docker-compose.yaml pull; then\n echo \"docker compose pull completed\"\n notify_host_hoot_info \"docker compose pull completed\"\nelse\n echo \"WARNING: docker compose pull failed; continuing with existing images\"\n notify_host_hoot_info \"docker compose pull failed; using existing images\"\nfi\n\necho \"Images after pull:\"\ndocker images --format '{{.Repository}}:{{.Tag}} {{.ID}} ({{.CreatedSince}})'\n\n#\n# Set root password.\n#\necho \"Setting root password..\"\n\n# Check if password files are writable\nPASSWD_WRITABLE=true\nif [ ! -w /etc/passwd ]; then\n echo \"Warning: /etc/passwd is read-only\"\n PASSWD_WRITABLE=false\nfi\nif [ ! -w /etc/shadow ]; then\n echo \"Warning: /etc/shadow is read-only\"\n PASSWD_WRITABLE=false\nfi\n\nif [ \"$PASSWD_WRITABLE\" = \"false\" ]; then\n echo \"Skipping password setup due to read-only file system\"\nelse\n # Check if chpasswd is available\n if command -v chpasswd >/dev/null 2>&1; then\n echo \"Using chpasswd method\"\n\n if [ -n \"$DSTACK_ROOT_PASSWORD\" ]; then\n echo \"Setting root password from user..\"\n echo \"root:$DSTACK_ROOT_PASSWORD\" | chpasswd\n unset DSTACK_ROOT_PASSWORD\n echo \"Root password set/updated from DSTACK_ROOT_PASSWORD\"\n elif [ -z \"$(grep '^root:' /etc/shadow 2>/dev/null | cut -d: -f2)\" ]; then\n echo \"Setting random root password..\"\n # dstack guest busybox lacks head -c (FANCY_HEAD off); dd is the\n # last pipeline command, so its 0 status masks tr's SIGPIPE exit.\n DSTACK_ROOT_PASSWORD=$(\n LC_ALL=C tr -dc 'A-Za-z0-9' < /dev/urandom | dd bs=1 count=32 2>/dev/null\n )\n echo \"root:$DSTACK_ROOT_PASSWORD\" | chpasswd\n unset DSTACK_ROOT_PASSWORD\n echo \"Root password set (random auto-init)\"\n else\n echo \"Root password already set; no changes.\"\n fi\n else\n # No chpasswd: do not pipe into interactive passwd(1). It often reads\n # /dev/tty and fails with \"password for root is unchanged\" during boot.\n echo \"Using passwd method\"\n\n if [ -n \"$DSTACK_ROOT_PASSWORD\" ]; then\n echo \"Setting root password from user..\"\n if command -v passwd >/dev/null 2>&1 && passwd --help 2>&1 | grep -q -- '--stdin'; then\n echo \"$DSTACK_ROOT_PASSWORD\" | passwd --stdin root\n elif command -v openssl >/dev/null 2>&1; then\n # busybox passwd has no --stdin; write the SHA-512 crypt hash\n # into /etc/shadow directly instead of driving interactive passwd.\n HASHED_ROOT_PASSWORD=$(openssl passwd -6 \"$DSTACK_ROOT_PASSWORD\")\n sed -i \"s|^root:[^:]*:|root:${HASHED_ROOT_PASSWORD}:|\" /etc/shadow\n unset HASHED_ROOT_PASSWORD\n else\n echo \"Error: cannot set DSTACK_ROOT_PASSWORD non-interactively\"\n echo \"Need chpasswd, passwd --stdin, or openssl\"\n exit 1\n fi\n unset DSTACK_ROOT_PASSWORD\n echo \"Root password set/updated from DSTACK_ROOT_PASSWORD\"\n elif [ -z \"$(grep '^root:' /etc/shadow 2>/dev/null | cut -d: -f2)\" ]; then\n # Never lock the account here: sshd built without PAM (dstack dev\n # images) treats a locked account as \"deny all authentication\",\n # which breaks public-key SSH too. Set a discarded random password\n # by writing its crypt hash into /etc/shadow directly.\n if command -v openssl >/dev/null 2>&1; then\n echo \"Setting random root password..\"\n DSTACK_ROOT_PASSWORD=$(\n LC_ALL=C tr -dc 'A-Za-z0-9' < /dev/urandom | dd bs=1 count=32 2>/dev/null\n )\n HASHED_ROOT_PASSWORD=$(openssl passwd -6 \"$DSTACK_ROOT_PASSWORD\")\n sed -i \"s|^root:[^:]*:|root:${HASHED_ROOT_PASSWORD}:|\" /etc/shadow\n unset DSTACK_ROOT_PASSWORD HASHED_ROOT_PASSWORD\n echo \"Root password set (random auto-init)\"\n else\n echo \"Warning: no openssl to hash a random password; leaving root password empty\"\n fi\n else\n echo \"Root password already set; no changes.\"\n fi\n fi\nfi\n\n#\n# Set SSH authorized keys\n#\nif mkdir -p /home/root/.ssh 2>/dev/null; then\n if [[ -n \"$DSTACK_ROOT_PUBLIC_KEY\" ]]; then\n echo \"$DSTACK_ROOT_PUBLIC_KEY\" > /home/root/.ssh/authorized_keys\n unset DSTACK_ROOT_PUBLIC_KEY\n echo \"Root public key set\"\n fi\n if [[ -n \"$DSTACK_AUTHORIZED_KEYS\" ]]; then\n echo \"$DSTACK_AUTHORIZED_KEYS\" > /home/root/.ssh/authorized_keys\n unset DSTACK_AUTHORIZED_KEYS\n echo \"Root authorized_keys set\"\n fi\n\n if [[ -f /dstack/user_config ]] && jq empty /dstack/user_config 2>/dev/null; then\n if [[ $(jq 'has(\"ssh_authorized_keys\")' /dstack/user_config 2>/dev/null) == \"true\" ]]; then\n # jq -r terminates the value with a newline; jq -j does not, which\n # both concatenated the next appended key onto the same line and\n # made line-based counting report one key fewer than the file holds.\n jq -r '.ssh_authorized_keys' /dstack/user_config >> /home/root/.ssh/authorized_keys\n # Drop duplicates and the blank line an empty key list produces.\n sort -u /home/root/.ssh/authorized_keys > /home/root/.ssh/authorized_keys.tmp\n mv /home/root/.ssh/authorized_keys.tmp /home/root/.ssh/authorized_keys\n KEY_COUNT=$(grep -c '^[^[:space:]]' /home/root/.ssh/authorized_keys || true)\n echo \"Set root authorized_keys from user preferences, total $KEY_COUNT keys\"\n print_authorized_key_fingerprints /home/root/.ssh/authorized_keys\n fi\n fi\nelse\n echo \"Warning: Cannot create /home/root/.ssh directory (read-only file system?)\"\n echo \"Skipping SSH key setup\"\nfi\n\n\nif [[ -S /var/run/dstack.sock ]]; then\n export DSTACK_APP_ID=$(curl -s --unix-socket /var/run/dstack.sock http://dstack/Info | jq -j .app_id)\nelif [[ -S /var/run/tappd.sock ]]; then\n export DSTACK_APP_ID=$(curl -s --unix-socket /var/run/tappd.sock http://dstack/prpc/Tappd.Info | jq -j .app_id)\nfi\n# Check if DSTACK_GATEWAY_DOMAIN is not set, try to get it from user_config or app-compose.json\n# Priority: user_config > app-compose.json\nif [[ -z \"$DSTACK_GATEWAY_DOMAIN\" ]]; then\n # First try to get from /dstack/user_config if it exists and is valid JSON\n if [[ -f /dstack/user_config ]] && jq empty /dstack/user_config 2>/dev/null; then\n if [[ $(jq 'has(\"default_gateway_domain\")' /dstack/user_config 2>/dev/null) == \"true\" ]]; then\n export DSTACK_GATEWAY_DOMAIN=$(jq -j '.default_gateway_domain' /dstack/user_config)\n fi\n fi\n\n # If still not set, try to get from app-compose.json\n if [[ -z \"$DSTACK_GATEWAY_DOMAIN\" ]] && [[ $(jq 'has(\"default_gateway_domain\")' app-compose.json) == \"true\" ]]; then\n export DSTACK_GATEWAY_DOMAIN=$(jq -j '.default_gateway_domain' app-compose.json)\n fi\nfi\nif [[ -n \"$DSTACK_GATEWAY_DOMAIN\" ]]; then\n export DSTACK_APP_DOMAIN=$DSTACK_APP_ID\".\"$DSTACK_GATEWAY_DOMAIN\nfi\n\necho \"----------------------------------------------\"\necho \"Script execution completed\"\necho \"----------------------------------------------\"","public_logs":false,"public_sysinfo":false,"public_tcbinfo":true,"runner":"docker-compose","secure_time":false,"storage_fs":"zfs","tproxy_enabled":true}cdi-phala-dstack-reconstruction-config.json{"schema_version":1,"app_id":"53b1afccdae26112c17e890b6c3586cfae7717ce","instance_id":"f97b08db8b2f8146eea750b43621840206d64095","compose_hash":"9dbf79e75ef4218f8355a31c5af7198ebe7fe4268230b18d3909604fb699592b","os_image_hash":"806a352e16175d90568de97dff563f31f680239e6b90e9b5b2e9141d0955b0d9","vm_config":{"spec_version":1,"os_image_hash":"806a352e16175d90568de97dff563f31f680239e6b90e9b5b2e9141d0955b0d9","cpu_count":192,"memory_size":1649267441664,"qemu_single_pass_add_pages":null,"pic":null,"qemu_version":"9.2.1","pci_hole64_size":1125899906842624,"hugepages":false,"num_gpus":8,"num_nvswitches":4,"hotplug_off":true,"image":"dstack-nvidia-0.5.9-806a352e","host_share_mode":"9p"}}docker.io/ritualnetwork/attested-alpine@sha256:2296aa2ab950dd79c04a077af8b8d7de1c86f3c2402e6415e753be63b75b6dabdocker.io/ritualnetwork/attested-bifrost@sha256:99687dd5b49bed19aff7b37f0ec22b0e145da9cb17e0096b415b2b3d41e3893fdocker.io/ritualnetwork/attested-dynamo-sglang@sha256:f769e1278140b2a396cb1248be0802d4b2360fef4f3ca0b6cf4acf2edcf132efdocker.io/ritualnetwork/attested-etcd@sha256:4c15df3a62f8ffb25007194b09ab89731bd8ae4cc98a5cccb76bceff8d257232docker.io/ritualnetwork/attested-nats@sha256:0275c31c7b0100817abd03a10dc519697f0fdc710de8fa8c5c7f7ad41607e542docker.io/ritualnetwork/attested-redis@sha256:ab7cc60b5a997c5df4241a7de2508af1a05d01ee2a7506565928af44263d8c56docker.io/ritualnetwork/attested-sglang-diffusion@sha256:4a4e3223abcb7f7323868be64ac00b7091ac87cbb052622c40e6c341419e4cffdocker.io/ritualnetwork/attested-sglang@sha256:636477429594b690d83a0bb086b04c52086390c63be78141918e356b04ae904edocker.io/ritualnetwork/rai-simple@sha256:d0269af97a4d722a48647d723e7aff8a5bddcd1977b64347c14d162c35cfc7f0docker.io/ritualnetwork/ritual-moai-gpu@sha256:2f6e0751cf2383cd67cc1510adcd70699bba402d7d6a8ee285e08f438ace2245docker.io/ritualnetwork/ritual-vllm-proxy-go:cf17d76-93d86b2-amd64@sha256:3b7b49baba9bad656403f9636ff5eecc7c6f8b9c612639c46ea9433c3afee83fDstack-TEE/meta-dstack@e3655d1390feee3736476f4bda35c4354b4a12fc · dstack reproduce script referenced by the platform profile
This workload records the opaque ID of the authority-accepted platform profile required to verify it.
pp_b06ed351-1955-476e-885a-883c5d9086d1
Download platform-profile bundle (.tar)
Follow the links from the workload ID to its measurements, images, and source code. Expand a check to see what it establishes and inspect the supporting evidence.
The provenance manifest is the central index for this workload. It records the expected TDX measurements, the locator and digest of each verification artifact, and the repository and commit for relevant source code. A verifier uses these references to obtain each available artifact, confirm that its bytes match the recorded digest, and supply the verified artifact to the corresponding verification check.
You select the workload ID. This report does not check its current on-chain capability assignment.
Workload ID being checked: 0x72dc7c30a672d1a7478545aa9721ceda889e91f7e4154617338b2d5b0331d6cf
Check the provenance record and confirm that its eight measurement values produce the selected workload ID.
| MRTD | 0xb24d3b24e9e3c16012376b52362ca09856c4adecb709d5fac33addf1c47e193da075b125b6c364115771390a5461e217 |
|---|---|
| RTMR0 | 0x90550e56509b94f99f4670a563e0dd0a2fa79b6d7b97fd52d051069d1b33d270b1858120034a43dac4f8daf509f2aeda |
| RTMR1 | 0x07e6f51aa763abfe75c3ddfbf4f425fe3f0ceff66d807a75e049303dce9addf68e7218729bd419638af63a370f65878c |
| RTMR2 | 0xf1c82667a354194467cd8419efd14a714560dd9b85b4c13b25c11e44bf4e126248c2255fad58c303fb0ca2921765d53a |
| RTMR3 | 0x3598be1aba8a82b8dcffeb9095184d7fac87311e4b8e599382ea3f6e2198168f59c2ad44550b266ef998e71632e18bac |
| MRCONFIGID | 0x019dbf79e75ef4218f8355a31c5af7198ebe7fe4268230b18d3909604fb699592b000000000000000000000000000000 |
| XFAM | 0xe702060000000000 |
| TD attributes | 0x0000001000000000 |
keccak256(mrTd || rtMr0 || rtMr1 || rtMr2 || rtMr3 || mrConfigId || xFAM || tdAttributes) ✓
= 0x72dc7c30a672d1a7478545aa9721ceda889e91f7e4154617338b2d5b0331d6cf
Use the verified prebuilt OS image, Docker images, Docker configuration, and TDX boot profile to recompute the eight TDX values. Compare each value with the expected measurements from step 2.
This check links the published OS artifact to its recorded source repository, commit, and build instructions. The service hashes the build instructions and OS artifact, compares them with the provenance manifest, and confirms that the recorded source and artifact values match an immutable platform-profile bundle selected from the service-owned accepted-profile registry. The workload record names the selected profile’s opaque ID; the registry binds that ID to the exact archive. Each check below links the exact files and source used, so you can inspect them or repeat the comparisons.
For Phala/dstack, the provider profile is accepted in a separate offline phase, where the service validates the published dstack release bundle, confirms its size and os_image_hash, and replays known measurement vectors with the pinned dstack-mr tool. The service does not rebuild the recorded meta-dstack commit; that separate source-to-release check can be repeated with Phala’s published reproduction script.
This check calculates the SHA-256 hash of the recorded dstack reproduce script and compares it with the expected digest in the provenance manifest. The evidence link below is the exact script published with the release, available if you want to inspect the build procedure or repeat the digest comparison.
Expected SHA-256 digest from the manifest:sha256:8d63a9bcf02ffb30f1e69af08d4683b13cf3bee1fef6db0bc066c351a178aa3f
Related evidence and source:
This check calculates the SHA-256 hash of the published dstack release bundle and compares it with the expected digest in the provenance manifest. The bundle contains the release metadata used by dstack-mr to reproduce the boot measurements.
Expected SHA-256 digest from the manifest:sha256:7a19dd759e65d25085e57de0cfa438c59754cd435c34aca31455f8993f06be2c
Related evidence and source:
This check confirms that the OS image hash selected by the VM configuration and the manifest’s source repository, commit, reproduce script, and release bundle match the accepted Phala profile. It also checks the release bundle’s expected size and extracts the exact release metadata used by dstack-mr.
Related evidence and source:
This check links the Docker workload inputs to the TDX measurements that commit to them. The service checks the exact measured configuration against its manifest digest, extracts its digest-pinned container images, and confirms that the image list exactly matches the Docker images declared in the manifest. This means the GitHub attestations in step 4 cover the container images committed to the TDX measurements. The provider-specific details below explain which configuration is measured and how it contributes to the TDX values.
For Phala/dstack, the measured configuration is the exact app_compose document, which contains the embedded Docker Compose file and other application policy. Here, we validate the connection between the Docker images and app_compose. The app_compose hash can then be connected to MRCONFIGID and to the compose-hash event replayed into RTMR3. The service publishes app_compose and the captured VM configuration so you can inspect the exact inputs or repeat the calculation.
This check calculates the SHA-256 hash of the exact app_compose JSON document and compares it with the expected digest in the provenance manifest. app_compose contains the dstack application policy and the embedded Docker Compose file used to launch the workload.
Expected SHA-256 digest from the manifest:sha256:9dbf79e75ef4218f8355a31c5af7198ebe7fe4268230b18d3909604fb699592b
Related evidence and source:
This check links the Docker images declared in the provenance manifest to the exact app_compose document committed into MRCONFIGID and RTMR3.
Related evidence and source:
The TDX boot profile is the provider-specific recipe that combines the selected VM image with the cloud platform’s firmware, virtual-machine configuration, VMM behavior, and TDX launch settings to reproduce the boot-related measurements. This check links the boot-related TDX measurements back to the boot profile that produced them. The service verifies the supplied artifacts against the provenance manifest and requires the provider-specific profile values to match an accepted provider profile.
For Phala/dstack, the published OS release supplies the exact boot artifacts used to reproduce MRTD, RTMR1, and RTMR2: the OVMF firmware, Linux kernel, initrd, root filesystem hash, and kernel command line. RTMR0 also depends on the VM launch configuration—CPU, memory, and devices—which OVMF records in its boot events. The captured event log preserves the OVMF event digests used to reproduce RTMR0 in the complete-tuple procedure below.
published dstack OVMF firmware → MRTD
VM launch configuration + captured OVMF events → RTMR0
published Linux kernel image → RTMR1
kernel command line + initrd + rootfs hash → RTMR2
offline-approved VMM launch-field profile → MRCONFIGID format, XFAM, TDATTRIBUTESThis public document binds one dstack VM configuration to the captured application, instance, exact app_compose hash, and OS image hash. The service checks those bindings and the VM resource and device settings against the captured Phala CVM and application-attestation records, then supplies the nested VM configuration and verified dstack release to dstack-mr. Reported TDX measurements and the redacted event log remain separate evidence and are not duplicated in this document. These settings are not required to match an offline-approved machine configuration.
Expected SHA-256 digest from the manifest:sha256:da3ecfe89cac299186c7102f50ea50b6f9b857b9ba6ab9274a74c0caddd6357e
Related evidence and source:
This check covers the MRCONFIGID format, XFAM, and TDATTRIBUTES values accepted during offline profile validation. The service verifies that the supplied profile’s bytes match the digest in the provenance manifest and that its decoded values exactly match a supported VMM launch configuration for the selected dstack release.
The profile selects the supported MRCONFIGID version 1 format. The verifier hashes the exact app_compose document and constructs the full field as 0x01 followed by SHA-256(app_compose) and 15 zero bytes. The profile supplies the format version; the workload configuration supplies the rest of the value.
These values are determined by the VMM’s launch configuration—essentially VM creation flags—rather than derived from guest source code. The verifier requires them to match the offline-approved Phala machine profile before using them in the reproduced TDX tuple. This ties the calculation to the launch flags accepted for the selected dstack release.
Expected SHA-256 digest from the manifest:sha256:9ae363b6e674662be7713cf8ffdf5973307f04b85690b29ecf5ded90de9335cd
Related evidence and source:
With the OS image, Docker configuration, and TDX boot profile established above, this section runs the provider-specific measurement procedure that ties them together. We use pinned binaries that calculate the resulting TDX measurements without needing to run a TDX machine, and link to their source code.
verified OS image + Docker configuration + TDX boot profile
↓
pinned measurement tool
↓
recomputed eight-field TDX tuple
↓
canonical output digest matches manifestFor Phala/dstack, the pinned dstack-mr binary calculates MRTD, RTMR1, and RTMR2 from the verified dstack release and VM settings. The verifier replays the captured IMR0 event digests for RTMR0, replays the dstack runtime-event chain for RTMR3, and derives MRCONFIGID, XFAM, and TDATTRIBUTES from the checked configuration.
This image supplies the dstack-acpi-tables helper and QEMU resources that dstack-mr needs to reproduce the VM’s platform-specific ACPI measurements. The service first confirms that the image’s OCI manifest matches the digest pinned by the accepted Phala profile. During measurement reproduction, it does not launch a nested container: the approved image identity selects the reviewed packaged helper, and the service hashes that helper binary immediately before running dstack-mr.
Related evidence and source:
This check calculates the SHA-256 hash of the recorded dstack-mr build instructions and compares it with the expected digest in the provenance manifest. The evidence and source links below identify the exact tool build accepted for this Phala release.
Expected SHA-256 digest from the manifest:sha256:3403e815b5a1eb40684a246084694c3ab5b6b9d5fa56a60ea4a7495cad7c03e9
Related evidence and source:
This check links the reproduced boot measurements to the exact dstack-mr implementation accepted for this Phala release. The service checks the tool’s version, source repository, commit, executable digest, build instructions, and reviewed helper image against the accepted profile, then hashes the executable and packaged helper again before running them.
Related evidence and source:
This check verifies the exact captured event log against its digest in the provenance manifest before measurement reproduction. The log contains the OVMF IMR0 event digests used to calculate RTMR0 and the dstack runtime-event chain used to calculate RTMR3. The complete-tuple procedure below replays both chains and requires a readable compose-hash event containing SHA-256(app_compose), followed by system-ready; other runtime events may remain digest-only so their contents are not published.
Expected SHA-256 digest from the manifest:sha256:b020870f9b392c893bd088f15ddb51312fc8e07e96a5fd5e5efd1f673f3dba25
Related evidence and source:
This check links the verified dstack release, VM configuration, app_compose, event log, and accepted machine profile into one reproduced eight-field TDX tuple.
MRCONFIGID = 0x01 || SHA-256(app_compose) || 15 zero bytesExpected SHA-256 digest for the canonical eight-field output from the manifest:sha256:628d8f47a5766f70fb7afdb8f4915656b14f000ee042a1c8ec2a2df002ddc29a
Related evidence and source:
Recomputes all eight TDX measurements from the OS image, workload configuration, and platform inputs, then compares them with the values shown in Source info.
provider reproduced all eight declared TDX fields
Related evidence and source:
Does each exact container image connect to the claimed source code and build workflow?
Checks that GitHub’s signed build attestation connects this exact Docker image to the linked source commit and build workflow.
Related evidence and source:
Checks that GitHub’s signed build attestation connects this exact Docker image to the linked source commit and build workflow.
Related evidence and source:
Checks that GitHub’s signed build attestation connects this exact Docker image to the linked source commit and build workflow.
Related evidence and source:
Checks that GitHub’s signed build attestation connects this exact Docker image to the linked source commit and build workflow.
Related evidence and source:
Checks that GitHub’s signed build attestation connects this exact Docker image to the linked source commit and build workflow.
Related evidence and source:
Checks that GitHub’s signed build attestation connects this exact Docker image to the linked source commit and build workflow.
Related evidence and source:
Checks that GitHub’s signed build attestation connects this exact Docker image to the linked source commit and build workflow.
Related evidence and source:
Checks that GitHub’s signed build attestation connects this exact Docker image to the linked source commit and build workflow.
Related evidence and source:
Checks that GitHub’s signed build attestation connects this exact Docker image to the linked source commit and build workflow.
Related evidence and source:
Checks that GitHub’s signed build attestation connects this exact Docker image to the linked source commit and build workflow.
Related evidence and source:
Checks that GitHub’s signed build attestation connects this exact Docker image to the linked source commit and build workflow.
Related evidence and source:
An independent OS rebuild is an offline step for the user. Matching the recorded OS to an approved profile in step 3 does not mean this request rebuilt it.
Reviewing whether the source is safe and appropriate for its capability is a human judgment. This report does not perform that audit.
This appendix lists every verification input. Retained files and directly addressable external references are linked.
This record measures the published Phala OS release with dstack-mr. Rebuilding that OS from source is an optional offline step you can run with Phala's reproduce.sh; this site does not perform it.