fix: [nomad-prep] P0 — rename lib/vault.sh + vault/ to action-vault namespace (#792)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
18190874ca
commit
e9a018db5c
18 changed files with 21 additions and 21 deletions
97
action-vault/SCHEMA.md
Normal file
97
action-vault/SCHEMA.md
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
# Vault Action TOML Schema
|
||||
|
||||
This document defines the schema for vault action TOML files used in the PR-based approval workflow (issue #74).
|
||||
|
||||
## File Location
|
||||
|
||||
Vault actions are stored in `vault/actions/<action-id>.toml` on the ops repo.
|
||||
|
||||
## Schema Definition
|
||||
|
||||
```toml
|
||||
# Required
|
||||
id = "publish-skill-20260331"
|
||||
formula = "clawhub-publish"
|
||||
context = "SKILL.md bumped to 0.3.0"
|
||||
|
||||
# Required secrets to inject (env vars)
|
||||
secrets = ["CLAWHUB_TOKEN"]
|
||||
|
||||
# Optional file-based credential mounts
|
||||
mounts = ["ssh"]
|
||||
|
||||
# Optional
|
||||
model = "sonnet"
|
||||
tools = ["clawhub"]
|
||||
timeout_minutes = 30
|
||||
blast_radius = "low" # optional: overrides policy.toml tier ("low"|"medium"|"high")
|
||||
```
|
||||
|
||||
## Field Specifications
|
||||
|
||||
### Required Fields
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `id` | string | Unique identifier for the vault action. Format: `<action-type>-<date>` (e.g., `publish-skill-20260331`) |
|
||||
| `formula` | string | Formula name from `formulas/` directory that defines the operational task to execute |
|
||||
| `context` | string | Human-readable explanation of why this action is needed. Used in PR description |
|
||||
| `secrets` | array of strings | List of secret names to inject into the execution environment. Only these secrets are passed to the container |
|
||||
|
||||
### Optional Fields
|
||||
|
||||
| Field | Type | Default | Description |
|
||||
|-------|------|---------|-------------|
|
||||
| `mounts` | array of strings | `[]` | Well-known mount aliases for file-based credentials. The dispatcher maps each alias to a read-only volume flag |
|
||||
| `model` | string | `sonnet` | Override the default Claude model for this action |
|
||||
| `tools` | array of strings | `[]` | MCP tools to enable during execution |
|
||||
| `timeout_minutes` | integer | `60` | Maximum execution time in minutes |
|
||||
| `blast_radius` | string | _(from policy.toml)_ | Override blast-radius tier for this invocation. Valid values: `"low"`, `"medium"`, `"high"`. See [docs/BLAST-RADIUS.md](../docs/BLAST-RADIUS.md) |
|
||||
|
||||
## Secret Names
|
||||
|
||||
Secret names must be defined in `.env.vault.enc` on the ops repo. The vault validates that requested secrets exist in the allowlist before execution.
|
||||
|
||||
Common secret names:
|
||||
- `CLAWHUB_TOKEN` - Token for ClawHub skill publishing
|
||||
- `GITHUB_TOKEN` - GitHub API token for repository operations
|
||||
- `DEPLOY_KEY` - Infrastructure deployment key
|
||||
|
||||
## Mount Aliases
|
||||
|
||||
Mount aliases map to read-only volume flags passed to the runner container:
|
||||
|
||||
| Alias | Maps to |
|
||||
|-------|---------|
|
||||
| `ssh` | `-v ${HOME}/.ssh:/home/agent/.ssh:ro` |
|
||||
| `gpg` | `-v ${HOME}/.gnupg:/home/agent/.gnupg:ro` |
|
||||
| `sops` | `-v ${HOME}/.config/sops/age:/home/agent/.config/sops/age:ro` |
|
||||
|
||||
## Validation Rules
|
||||
|
||||
1. **Required fields**: `id`, `formula`, `context`, and `secrets` must be present
|
||||
2. **Formula validation**: The formula must exist in the `formulas/` directory
|
||||
3. **Secret validation**: All secrets in the `secrets` array must be in the allowlist
|
||||
4. **No unknown fields**: The TOML must not contain fields outside the schema
|
||||
5. **ID uniqueness**: The `id` must be unique across all vault actions
|
||||
|
||||
## Example Files
|
||||
|
||||
See `vault/examples/` for complete examples:
|
||||
- `webhook-call.toml` - Example of calling an external webhook
|
||||
- `promote.toml` - Example of promoting a build/artifact
|
||||
- `publish.toml` - Example of publishing a skill to ClawHub
|
||||
|
||||
## Usage
|
||||
|
||||
Validate a vault action file:
|
||||
|
||||
```bash
|
||||
./vault/validate.sh vault/actions/<action-id>.toml
|
||||
```
|
||||
|
||||
The validator will check:
|
||||
- All required fields are present
|
||||
- Secret names are in the allowlist
|
||||
- No unknown fields are present
|
||||
- Formula exists in the formulas directory
|
||||
53
action-vault/classify.sh
Executable file
53
action-vault/classify.sh
Executable file
|
|
@ -0,0 +1,53 @@
|
|||
#!/usr/bin/env bash
|
||||
# classify.sh — Blast-radius classification engine
|
||||
#
|
||||
# Reads the ops-repo policy.toml and prints the tier for a given formula.
|
||||
# An optional blast_radius override (from the action TOML) takes precedence.
|
||||
#
|
||||
# Usage: classify.sh <formula-name> [blast_radius_override]
|
||||
# Output: prints "low", "medium", or "high" to stdout; exits 0
|
||||
#
|
||||
# Source lib/env.sh directly (not vault-env.sh) to avoid circular dependency:
|
||||
# vault-env.sh calls classify.sh, so classify.sh must not source vault-env.sh.
|
||||
# The only variable needed here is OPS_REPO_ROOT, which comes from lib/env.sh.
|
||||
# shellcheck source=../lib/env.sh
|
||||
set -euo pipefail
|
||||
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/lib/env.sh"
|
||||
|
||||
formula="${1:-}"
|
||||
override="${2:-}"
|
||||
|
||||
if [ -z "$formula" ]; then
|
||||
echo "Usage: classify.sh <formula-name> [blast_radius_override]" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# If the action TOML provides a blast_radius override, use it directly
|
||||
if [[ "$override" =~ ^(low|medium|high)$ ]]; then
|
||||
echo "$override"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Read tier from ops-repo policy.toml
|
||||
policy_file="${OPS_REPO_ROOT}/vault/policy.toml"
|
||||
|
||||
if [ -f "$policy_file" ]; then
|
||||
# Parse: look for `formula_name = "tier"` under [tiers]
|
||||
# Escape regex metacharacters in formula name for safe grep
|
||||
escaped_formula=$(printf '%s' "$formula" | sed 's/[].[*^$\\]/\\&/g')
|
||||
# grep may find no match (exit 1); guard with || true to avoid pipefail abort
|
||||
tier=$(sed -n '/^\[tiers\]/,/^\[/{/^\[tiers\]/d;/^\[/d;p}' "$policy_file" \
|
||||
| { grep -E "^${escaped_formula}[[:space:]]*=" || true; } \
|
||||
| sed -E 's/^[^=]+=[[:space:]]*"([^"]+)".*/\1/' \
|
||||
| head -n1)
|
||||
|
||||
if [[ "$tier" =~ ^(low|medium|high)$ ]]; then
|
||||
echo "$tier"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Default-deny: unknown formulas are high
|
||||
echo "high"
|
||||
exit 0
|
||||
21
action-vault/examples/promote.toml
Normal file
21
action-vault/examples/promote.toml
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# vault/examples/promote.toml
|
||||
# Example: Promote a build/artifact to production
|
||||
#
|
||||
# This vault action demonstrates promoting a built artifact to a
|
||||
# production environment with proper authentication.
|
||||
|
||||
id = "promote-20260331"
|
||||
formula = "run-supervisor"
|
||||
context = "Promote build v1.2.3 to production environment"
|
||||
|
||||
# Secrets to inject for deployment authentication
|
||||
secrets = ["DEPLOY_KEY", "DOCKER_HUB_TOKEN"]
|
||||
|
||||
# Optional: use larger model for complex deployment logic
|
||||
model = "sonnet"
|
||||
|
||||
# Optional: enable MCP tools for container operations
|
||||
tools = ["docker"]
|
||||
|
||||
# Optional: deployments may take longer
|
||||
timeout_minutes = 45
|
||||
21
action-vault/examples/publish.toml
Normal file
21
action-vault/examples/publish.toml
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# vault/examples/publish.toml
|
||||
# Example: Publish a skill to ClawHub
|
||||
#
|
||||
# This vault action demonstrates publishing a skill to ClawHub
|
||||
# using the clawhub-publish formula.
|
||||
|
||||
id = "publish-site-20260331"
|
||||
formula = "run-publish-site"
|
||||
context = "Publish updated site to production"
|
||||
|
||||
# Secrets to inject (only these get passed to the container)
|
||||
secrets = ["DEPLOY_KEY"]
|
||||
|
||||
# Optional: use sonnet model
|
||||
model = "sonnet"
|
||||
|
||||
# Optional: enable MCP tools
|
||||
tools = []
|
||||
|
||||
# Optional: 30 minute timeout
|
||||
timeout_minutes = 30
|
||||
37
action-vault/examples/release.toml
Normal file
37
action-vault/examples/release.toml
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# vault/examples/release.toml
|
||||
# Example: Release vault item schema
|
||||
#
|
||||
# This example demonstrates the release vault item schema for creating
|
||||
# versioned releases with vault-gated approval.
|
||||
#
|
||||
# The release formula tags Forgejo main, pushes to mirrors, builds and
|
||||
# tags the agents Docker image, and restarts agent containers.
|
||||
#
|
||||
# Example vault item (auto-generated by `disinto release v1.2.0`):
|
||||
#
|
||||
# id = "release-v120"
|
||||
# formula = "release"
|
||||
# context = "Release v1.2.0"
|
||||
# secrets = []
|
||||
# mounts = ["ssh"]
|
||||
#
|
||||
# Steps executed by the release formula:
|
||||
# 1. preflight - Validate prerequisites (version, FORGE_TOKEN, Docker)
|
||||
# 2. tag-main - Create tag on Forgejo main via API
|
||||
# 3. push-mirrors - Push tag to Codeberg and GitHub mirrors
|
||||
# 4. build-image - Build agents Docker image with --no-cache
|
||||
# 5. tag-image - Tag image with version (disinto-agents:v1.2.0)
|
||||
# 6. restart-agents - Restart agent containers with new image
|
||||
# 7. commit-result - Write release result to tracking file
|
||||
|
||||
id = "release-v120"
|
||||
formula = "release"
|
||||
context = "Release v1.2.0 — includes vault redesign, .profile system, architect agent"
|
||||
secrets = ["GITHUB_TOKEN", "CODEBERG_TOKEN"]
|
||||
mounts = ["ssh"]
|
||||
|
||||
# Optional: specify a larger model for complex release logic
|
||||
# model = "sonnet"
|
||||
|
||||
# Optional: releases may take longer due to Docker builds
|
||||
# timeout_minutes = 60
|
||||
21
action-vault/examples/webhook-call.toml
Normal file
21
action-vault/examples/webhook-call.toml
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# vault/examples/webhook-call.toml
|
||||
# Example: Call an external webhook with authentication
|
||||
#
|
||||
# This vault action demonstrates calling an external webhook endpoint
|
||||
# with proper authentication via injected secrets.
|
||||
|
||||
id = "webhook-call-20260331"
|
||||
formula = "run-rent-a-human"
|
||||
context = "Notify Slack channel about deployment completion"
|
||||
|
||||
# Secrets to inject (only these get passed to the container)
|
||||
secrets = ["DEPLOY_KEY"]
|
||||
|
||||
# Optional: use sonnet model for this action
|
||||
model = "sonnet"
|
||||
|
||||
# Optional: enable MCP tools
|
||||
tools = []
|
||||
|
||||
# Optional: 30 minute timeout
|
||||
timeout_minutes = 30
|
||||
30
action-vault/policy.toml
Normal file
30
action-vault/policy.toml
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# vault/policy.toml — Blast-radius tier classification for formulas
|
||||
#
|
||||
# Each formula maps to a tier: "low", "medium", or "high".
|
||||
# Unknown formulas default to "high" (default-deny).
|
||||
#
|
||||
# This file is a template. `disinto init` copies it to
|
||||
# $OPS_REPO_ROOT/vault/policy.toml where operators can override tiers
|
||||
# per-deployment without a disinto PR.
|
||||
|
||||
[tiers]
|
||||
# Read-only / internal bookkeeping — no external side-effects
|
||||
groom-backlog = "low"
|
||||
triage = "low"
|
||||
reproduce = "low"
|
||||
review-pr = "low"
|
||||
|
||||
# Create issues, PRs, or internal plans — visible but reversible
|
||||
dev = "medium"
|
||||
run-planner = "medium"
|
||||
run-gardener = "medium"
|
||||
run-predictor = "medium"
|
||||
run-supervisor = "medium"
|
||||
run-architect = "medium"
|
||||
upgrade-dependency = "medium"
|
||||
|
||||
# External-facing or irreversible operations
|
||||
run-publish-site = "high"
|
||||
run-rent-a-human = "high"
|
||||
add-rpc-method = "high"
|
||||
release = "high"
|
||||
47
action-vault/validate.sh
Executable file
47
action-vault/validate.sh
Executable file
|
|
@ -0,0 +1,47 @@
|
|||
#!/usr/bin/env bash
|
||||
# vault/validate.sh — Validate vault action TOML files
|
||||
#
|
||||
# Usage: ./vault/validate.sh <path-to-toml>
|
||||
#
|
||||
# Validates a vault action TOML file according to the schema defined in
|
||||
# vault/SCHEMA.md. Checks:
|
||||
# - Required fields are present
|
||||
# - Secret names are in the allowlist
|
||||
# - No unknown fields are present
|
||||
# - Formula exists in formulas/
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Get script directory
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# Source vault environment
|
||||
source "$SCRIPT_DIR/vault-env.sh"
|
||||
|
||||
# Get the TOML file to validate
|
||||
TOML_FILE="${1:-}"
|
||||
|
||||
if [ -z "$TOML_FILE" ]; then
|
||||
echo "Usage: $0 <path-to-toml>" >&2
|
||||
echo "Example: $0 vault/examples/publish.toml" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Resolve relative paths
|
||||
if [[ "$TOML_FILE" != /* ]]; then
|
||||
TOML_FILE="$(cd "$(dirname "$TOML_FILE")" && pwd)/$(basename "$TOML_FILE")"
|
||||
fi
|
||||
|
||||
# Run validation
|
||||
if validate_vault_action "$TOML_FILE"; then
|
||||
echo "VALID: $TOML_FILE"
|
||||
echo " ID: $VAULT_ACTION_ID"
|
||||
echo " Formula: $VAULT_ACTION_FORMULA"
|
||||
echo " Context: $VAULT_ACTION_CONTEXT"
|
||||
echo " Secrets: $VAULT_ACTION_SECRETS"
|
||||
echo " Mounts: ${VAULT_ACTION_MOUNTS:-none}"
|
||||
exit 0
|
||||
else
|
||||
echo "INVALID: $TOML_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
190
action-vault/vault-env.sh
Normal file
190
action-vault/vault-env.sh
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
#!/usr/bin/env bash
|
||||
# vault-env.sh — Shared vault environment: loads lib/env.sh and activates
|
||||
# vault-bot's Forgejo identity (#747).
|
||||
# Source this instead of lib/env.sh in vault scripts.
|
||||
|
||||
# shellcheck source=../lib/env.sh
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/lib/env.sh"
|
||||
# Use vault-bot's own Forgejo identity
|
||||
FORGE_TOKEN="${FORGE_VAULT_TOKEN:-${FORGE_TOKEN}}"
|
||||
export FORGE_TOKEN
|
||||
|
||||
# Export FORGE_ADMIN_TOKEN for direct commits (low-tier bypass)
|
||||
# This token is used to commit directly to ops main without PR workflow
|
||||
export FORGE_ADMIN_TOKEN="${FORGE_ADMIN_TOKEN:-}"
|
||||
|
||||
# Vault redesign in progress (PR-based approval workflow)
|
||||
# This file is kept for shared env setup; scripts being replaced by #73
|
||||
|
||||
# Blast-radius classification — set VAULT_TIER if a formula is known
|
||||
# Callers may set VAULT_ACTION_FORMULA before sourcing, or pass it later.
|
||||
if [ -n "${VAULT_ACTION_FORMULA:-}" ]; then
|
||||
VAULT_TIER=$("$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/classify.sh" \
|
||||
"$VAULT_ACTION_FORMULA" "${VAULT_BLAST_RADIUS_OVERRIDE:-}")
|
||||
export VAULT_TIER
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# VAULT ACTION VALIDATION
|
||||
# =============================================================================
|
||||
|
||||
# Allowed secret names - must match keys in .env.vault.enc
|
||||
VAULT_ALLOWED_SECRETS="CLAWHUB_TOKEN GITHUB_TOKEN CODEBERG_TOKEN DEPLOY_KEY NPM_TOKEN DOCKER_HUB_TOKEN"
|
||||
|
||||
# Allowed mount aliases — well-known file-based credential directories
|
||||
VAULT_ALLOWED_MOUNTS="ssh gpg sops"
|
||||
|
||||
# Validate a vault action TOML file
|
||||
# Usage: validate_vault_action <path-to-toml>
|
||||
# Returns: 0 if valid, 1 if invalid
|
||||
# Sets: VAULT_ACTION_ID, VAULT_ACTION_FORMULA, VAULT_ACTION_CONTEXT on success
|
||||
validate_vault_action() {
|
||||
local toml_file="$1"
|
||||
|
||||
if [ -z "$toml_file" ]; then
|
||||
echo "ERROR: No TOML file specified" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$toml_file" ]; then
|
||||
echo "ERROR: File not found: $toml_file" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
log "Validating vault action: $toml_file"
|
||||
|
||||
# Get script directory for relative path resolution
|
||||
# FACTORY_ROOT is set by lib/env.sh which is sourced above
|
||||
local formulas_dir="${FACTORY_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}/formulas"
|
||||
|
||||
# Extract TOML values using grep/sed (basic TOML parsing)
|
||||
local toml_content
|
||||
toml_content=$(cat "$toml_file")
|
||||
|
||||
# Extract string values (id, formula, context)
|
||||
local id formula context
|
||||
id=$(echo "$toml_content" | grep -E '^id\s*=' | sed -E 's/^id\s*=\s*"(.*)"/\1/' | tr -d '\r')
|
||||
formula=$(echo "$toml_content" | grep -E '^formula\s*=' | sed -E 's/^formula\s*=\s*"(.*)"/\1/' | tr -d '\r')
|
||||
context=$(echo "$toml_content" | grep -E '^context\s*=' | sed -E 's/^context\s*=\s*"(.*)"/\1/' | tr -d '\r')
|
||||
|
||||
# Extract secrets array
|
||||
local secrets_line secrets_array
|
||||
secrets_line=$(echo "$toml_content" | grep -E '^secrets\s*=' | tr -d '\r')
|
||||
secrets_array=$(echo "$secrets_line" | sed -E 's/^secrets\s*=\s*\[(.*)\]/\1/' | tr -d '[]"' | tr ',' ' ' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
||||
|
||||
# Extract mounts array (optional)
|
||||
local mounts_line mounts_array
|
||||
mounts_line=$(echo "$toml_content" | grep -E '^mounts\s*=' | tr -d '\r') || true
|
||||
mounts_array=$(echo "$mounts_line" | sed -E 's/^mounts\s*=\s*\[(.*)\]/\1/' | tr -d '[]"' | tr ',' ' ' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') || true
|
||||
|
||||
# Check for unknown fields (any top-level key not in allowed list)
|
||||
local unknown_fields
|
||||
unknown_fields=$(echo "$toml_content" | grep -E '^[a-zA-Z_][a-zA-Z0-9_]*\s*=' | sed -E 's/^([a-zA-Z_][a-zA-Z0-9_]*)\s*=.*/\1/' | sort -u | while read -r field; do
|
||||
case "$field" in
|
||||
id|formula|context|secrets|mounts|model|tools|timeout_minutes|dispatch_mode|blast_radius) ;;
|
||||
*) echo "$field" ;;
|
||||
esac
|
||||
done)
|
||||
|
||||
if [ -n "$unknown_fields" ]; then
|
||||
echo "ERROR: Unknown fields in TOML: $(echo "$unknown_fields" | tr '\n' ', ' | sed 's/,$//')" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Validate required fields
|
||||
if [ -z "$id" ]; then
|
||||
echo "ERROR: Missing required field: id" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$formula" ]; then
|
||||
echo "ERROR: Missing required field: formula" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$context" ]; then
|
||||
echo "ERROR: Missing required field: context" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Validate formula exists in formulas/ (.toml for Claude reasoning, .sh for mechanical)
|
||||
if [ ! -f "$formulas_dir/${formula}.toml" ] && [ ! -f "$formulas_dir/${formula}.sh" ]; then
|
||||
echo "ERROR: Formula not found: $formula (checked .toml and .sh)" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Validate secrets field exists and is not empty
|
||||
if [ -z "$secrets_line" ]; then
|
||||
echo "ERROR: Missing required field: secrets" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Validate each secret is in the allowlist
|
||||
for secret in $secrets_array; do
|
||||
secret=$(echo "$secret" | tr -d '"' | xargs) # trim whitespace and quotes
|
||||
if [ -n "$secret" ]; then
|
||||
if ! echo " $VAULT_ALLOWED_SECRETS " | grep -q " $secret "; then
|
||||
echo "ERROR: Unknown secret (not in allowlist): $secret" >&2
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Validate each mount alias is in the allowlist
|
||||
if [ -n "$mounts_array" ]; then
|
||||
for mount in $mounts_array; do
|
||||
mount=$(echo "$mount" | tr -d '"' | xargs) # trim whitespace and quotes
|
||||
if [ -n "$mount" ]; then
|
||||
if ! echo " $VAULT_ALLOWED_MOUNTS " | grep -q " $mount "; then
|
||||
echo "ERROR: Unknown mount alias (not in allowlist): $mount" >&2
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Validate optional fields if present
|
||||
# model
|
||||
if echo "$toml_content" | grep -qE '^model\s*='; then
|
||||
local model_value
|
||||
model_value=$(echo "$toml_content" | grep -E '^model\s*=' | sed -E 's/^model\s*=\s*"(.*)"/\1/' | tr -d '\r')
|
||||
if [ -z "$model_value" ]; then
|
||||
echo "ERROR: 'model' must be a non-empty string" >&2
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# tools
|
||||
if echo "$toml_content" | grep -qE '^tools\s*='; then
|
||||
local tools_line
|
||||
tools_line=$(echo "$toml_content" | grep -E '^tools\s*=' | tr -d '\r')
|
||||
if ! echo "$tools_line" | grep -q '\['; then
|
||||
echo "ERROR: 'tools' must be an array" >&2
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# timeout_minutes
|
||||
if echo "$toml_content" | grep -qE '^timeout_minutes\s*='; then
|
||||
local timeout_value
|
||||
timeout_value=$(echo "$toml_content" | grep -E '^timeout_minutes\s*=' | sed -E 's/^timeout_minutes\s*=\s*([0-9]+)/\1/' | tr -d '\r')
|
||||
if [ -z "$timeout_value" ] || [ "$timeout_value" -le 0 ] 2>/dev/null; then
|
||||
echo "ERROR: 'timeout_minutes' must be a positive integer" >&2
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Export validated values (for use by caller script)
|
||||
export VAULT_ACTION_ID="$id"
|
||||
export VAULT_ACTION_FORMULA="$formula"
|
||||
export VAULT_ACTION_CONTEXT="$context"
|
||||
export VAULT_ACTION_SECRETS="$secrets_array"
|
||||
export VAULT_ACTION_MOUNTS="${mounts_array:-}"
|
||||
|
||||
log "VAULT_ACTION_ID=$VAULT_ACTION_ID"
|
||||
log "VAULT_ACTION_FORMULA=$VAULT_ACTION_FORMULA"
|
||||
log "VAULT_ACTION_SECRETS=$VAULT_ACTION_SECRETS"
|
||||
log "VAULT_ACTION_MOUNTS=${VAULT_ACTION_MOUNTS:-none}"
|
||||
|
||||
return 0
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue