Spaces:
Runtime error
Runtime error
| set -euo pipefail | |
| ROOT="$(cd "$(dirname "$0")/.." && pwd)" | |
| MANIFEST_PATH="${1:-}" | |
| POLICY_PATH="$ROOT/policy/exec_allowlist_v0.json" | |
| if [ -z "$MANIFEST_PATH" ]; then | |
| echo "usage: ./runtime/execute_manifest.sh <manifest.json>" >&2 | |
| exit 1 | |
| fi | |
| if [ ! -f "$MANIFEST_PATH" ]; then | |
| echo "manifest not found: $MANIFEST_PATH" >&2 | |
| exit 1 | |
| fi | |
| MANIFEST_ABS="$(cd "$(dirname "$MANIFEST_PATH")" && pwd)/$(basename "$MANIFEST_PATH")" | |
| INPUT_SHA256="$(shasum -a 256 "$MANIFEST_ABS" | awk '{print $1}')" | |
| DOC_KIND="$(jq -r 'if .version == "work_manifest_v0" then "work_manifest" elif has("task_id") and has("operations") then "utir" else "unknown" end' "$MANIFEST_ABS")" | |
| if [ "$DOC_KIND" = "unknown" ]; then | |
| echo "unsupported manifest packet: $MANIFEST_ABS" >&2 | |
| exit 1 | |
| fi | |
| DOC_ID="$(jq -r 'if has("manifest_id") then .manifest_id else .task_id end' "$MANIFEST_ABS")" | |
| DOC_GOAL="$(jq -r 'if has("goal") then .goal else .description end' "$MANIFEST_ABS")" | |
| DOC_LANE="$(jq -r 'if has("lane") then .lane else "execution" end' "$MANIFEST_ABS")" | |
| RUN_ID="$(date -u +"%Y%m%dT%H%M%SZ")-$DOC_ID" | |
| OUT_DIR="$ROOT/runs/runtime/$RUN_ID" | |
| RECEIPT_PATH="$OUT_DIR/receipt.json" | |
| SUMMARY_PATH="$OUT_DIR/summary.json" | |
| GRAPH_PATH="$OUT_DIR/graph_state.json" | |
| EFFECTS_NDJSON="$OUT_DIR/effects.ndjson" | |
| mkdir -p "$OUT_DIR" | |
| : > "$EFFECTS_NDJSON" | |
| if [ "$DOC_KIND" = "work_manifest" ]; then | |
| EXECUTION_GATE="$(jq -r '.execution_gate' "$MANIFEST_ABS")" | |
| if [ "$EXECUTION_GATE" != "true" ]; then | |
| echo "execution gate is closed in manifest: $MANIFEST_ABS" >&2 | |
| exit 1 | |
| fi | |
| fi | |
| append_effect() { | |
| printf '%s\n' "$1" >> "$EFFECTS_NDJSON" | |
| } | |
| file_sha_or_null() { | |
| local file="$1" | |
| if [ -s "$file" ]; then | |
| shasum -a 256 "$file" | awk '{print $1}' | |
| else | |
| echo "" | |
| fi | |
| } | |
| is_command_allowed() { | |
| local cmd="$1" | |
| local first_word | |
| first_word="$(printf '%s' "$cmd" | awk '{print $1}')" | |
| if [ -z "$first_word" ]; then | |
| return 1 | |
| fi | |
| if jq -e --arg cmd "$first_word" '.allowed_commands | index($cmd)' "$POLICY_PATH" >/dev/null; then | |
| return 0 | |
| fi | |
| return 1 | |
| } | |
| has_blocked_pattern() { | |
| local cmd="$1" | |
| while IFS= read -r pattern; do | |
| [ -z "$pattern" ] && continue | |
| case "$cmd" in | |
| *"$pattern"*) return 0 ;; | |
| esac | |
| done < <(jq -r '.blocked_patterns[]' "$POLICY_PATH") | |
| return 1 | |
| } | |
| is_path_allowed() { | |
| local rel="$1" | |
| while IFS= read -r prefix; do | |
| [ -z "$prefix" ] && continue | |
| case "$rel" in | |
| "$prefix"*) return 0 ;; | |
| esac | |
| done < <(jq -r '.sandbox_prefixes[]' "$POLICY_PATH") | |
| return 1 | |
| } | |
| ACTION_COUNT="$(jq '.actions | length' "$MANIFEST_ABS")" | |
| if [ "$DOC_KIND" = "utir" ]; then | |
| ACTION_COUNT="$(jq '.operations | length' "$MANIFEST_ABS")" | |
| fi | |
| normalize_type() { | |
| local raw="$1" | |
| case "$DOC_KIND:$raw" in | |
| work_manifest:write_file) echo "write_file" ;; | |
| work_manifest:exec) echo "exec" ;; | |
| utir:fs.write) echo "write_file" ;; | |
| utir:shell) echo "exec" ;; | |
| *) echo "unsupported" ;; | |
| esac | |
| } | |
| if [ "$ACTION_COUNT" -eq 0 ]; then | |
| echo "no actions to execute: $MANIFEST_ABS" >&2 | |
| exit 1 | |
| fi | |
| for idx in $(seq 0 $((ACTION_COUNT - 1))); do | |
| ACTION="$(jq -c "if \"$DOC_KIND\" == \"work_manifest\" then .actions[$idx] else .operations[$idx] end" "$MANIFEST_ABS")" | |
| RAW_TYPE="$(printf '%s' "$ACTION" | jq -r '.type')" | |
| TYPE="$(normalize_type "$RAW_TYPE")" | |
| case "$TYPE" in | |
| write_file) | |
| REL_PATH="$(printf '%s' "$ACTION" | jq -r '.path')" | |
| if ! is_path_allowed "$REL_PATH"; then | |
| append_effect "$(jq -n \ | |
| --arg path "$REL_PATH" \ | |
| '{kind:"blocked",op:("write_file:" + $path),reason:"path blocked by local policy"}')" | |
| continue | |
| fi | |
| CONTENT="$(printf '%s' "$ACTION" | jq -r '.content')" | |
| TARGET_PATH="$ROOT/$REL_PATH" | |
| mkdir -p "$(dirname "$TARGET_PATH")" | |
| printf '%s' "$CONTENT" > "$TARGET_PATH" | |
| BYTES="$(wc -c < "$TARGET_PATH" | tr -d ' ')" | |
| SHA="$(shasum -a 256 "$TARGET_PATH" | awk '{print $1}')" | |
| append_effect "$(jq -n \ | |
| --arg path "$REL_PATH" \ | |
| --arg sha256 "$SHA" \ | |
| --argjson bytes "$BYTES" \ | |
| '{kind:"write_file",path:$path,bytes:$bytes,sha256:$sha256,ok:true,error:null}')" | |
| ;; | |
| exec) | |
| CMD="$(printf '%s' "$ACTION" | jq -r 'if has("cmd") then .cmd else .command end')" | |
| if has_blocked_pattern "$CMD"; then | |
| append_effect "$(jq -n \ | |
| --arg cmd "$CMD" \ | |
| '{kind:"blocked",op:("exec:" + $cmd),reason:"command blocked by local policy pattern"}')" | |
| elif ! is_command_allowed "$CMD"; then | |
| append_effect "$(jq -n \ | |
| --arg cmd "$CMD" \ | |
| '{kind:"blocked",op:("exec:" + $cmd),reason:"command not present in local allowlist"}')" | |
| else | |
| STDOUT_FILE="$OUT_DIR/exec-$idx.stdout" | |
| STDERR_FILE="$OUT_DIR/exec-$idx.stderr" | |
| set +e | |
| sh -lc "$CMD" >"$STDOUT_FILE" 2>"$STDERR_FILE" | |
| STATUS="$?" | |
| set -e | |
| STDOUT_SHA="$(file_sha_or_null "$STDOUT_FILE")" | |
| STDERR_SHA="$(file_sha_or_null "$STDERR_FILE")" | |
| append_effect "$(jq -n \ | |
| --arg cmd "$CMD" \ | |
| --argjson ok "$([ "$STATUS" -eq 0 ] && echo true || echo false)" \ | |
| --argjson status "$STATUS" \ | |
| --arg stdout_sha256 "$STDOUT_SHA" \ | |
| --arg stderr_sha256 "$STDERR_SHA" \ | |
| '{ | |
| kind:"exec", | |
| cmd:$cmd, | |
| ok:$ok, | |
| status:$status, | |
| stdout_sha256:(if $stdout_sha256 == "" then null else $stdout_sha256 end), | |
| stderr_sha256:(if $stderr_sha256 == "" then null else $stderr_sha256 end), | |
| error:(if $ok then null else "command failed" end) | |
| }')" | |
| fi | |
| ;; | |
| *) | |
| append_effect "$(jq -n \ | |
| --arg op "$RAW_TYPE" \ | |
| '{kind:"blocked",op:$op,reason:"unsupported action type for local runtime"}')" | |
| ;; | |
| esac | |
| done | |
| EFFECTS_JSON="$(jq -s '.' "$EFFECTS_NDJSON")" | |
| jq -n \ | |
| --arg version "receipt_v1" \ | |
| --argjson deterministic false \ | |
| --arg input_sha256 "$INPUT_SHA256" \ | |
| --argjson effects "$EFFECTS_JSON" \ | |
| '{ | |
| version:$version, | |
| deterministic:$deterministic, | |
| input_sha256:$input_sha256, | |
| generated_at_ms:null, | |
| effects:$effects | |
| }' > "$RECEIPT_PATH" | |
| jq -n \ | |
| --arg manifest "$MANIFEST_ABS" \ | |
| --arg receipt "$RECEIPT_PATH" \ | |
| --arg graph "$GRAPH_PATH" \ | |
| --arg run_id "$RUN_ID" \ | |
| --arg doc_kind "$DOC_KIND" \ | |
| --argjson action_count "$ACTION_COUNT" \ | |
| '{ | |
| run_id:$run_id, | |
| manifest:$manifest, | |
| document_kind:$doc_kind, | |
| receipt:$receipt, | |
| graph_state:$graph, | |
| action_count:$action_count | |
| }' > "$SUMMARY_PATH" | |
| jq -n \ | |
| --arg run_id "$RUN_ID" \ | |
| --arg manifest_id "$DOC_ID" \ | |
| --arg goal "$DOC_GOAL" \ | |
| --arg lane "$DOC_LANE" \ | |
| --arg receipt "$RECEIPT_PATH" \ | |
| --argjson execution_allowed true \ | |
| --arg doc_kind "$DOC_KIND" \ | |
| --argjson effects "$EFFECTS_JSON" \ | |
| '{ | |
| run_id:$run_id, | |
| manifest_id:$manifest_id, | |
| document_kind:$doc_kind, | |
| goal:$goal, | |
| lane:$lane, | |
| execution_gate:{allowed:$execution_allowed}, | |
| receipt:$receipt, | |
| effects:$effects | |
| }' > "$GRAPH_PATH" | |
| printf '%s\n' "$RECEIPT_PATH" | |
| printf '%s\n' "$SUMMARY_PATH" | |