Remediate six confirmed security issues: deployment-only config keys, bounded provider responses, short-lived registration sessions, private init file mode, FedWiki workflow authorization, and switch preview gates. - Add DeploymentOnly config key declaration; refuse runtime overrides for keys that decide where secrets are sent - Create httplimit package; bound all provider response reads at 8 MiB - Set fifteen-minute deadline on /register sessions - Write mc-config.yaml with 0600 permissions - Derive FedWiki workflow IDs from site IDs; re-authorize sites before mutating activities - Apply switch authorization gates to the proration preview
105 lines
5.7 KiB
Bash
Executable File
105 lines
5.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Ideation lane: run outside models on a design brief, one lane per provider,
|
|
# inside the same contained container the security lane uses. The container
|
|
# sees a disposable git-archive copy of HEAD and can reach only the model APIs.
|
|
#
|
|
# The brief is yours, not the runner's. Pass the directory holding it; it must
|
|
# contain DESIGNER.md (how the model works and what it must produce),
|
|
# CONTEXT.md (the surface and its constraints), SCREENS.md (what exists today)
|
|
# and brief.md (the deliverable). Override any one with the matching variable.
|
|
#
|
|
# Usage:
|
|
# ./prepare.sh # once: export HEAD, build, start proxy
|
|
# ./run-ux.sh <brief-dir> # default four models
|
|
# MODELS="zai-coding-plan/glm-5.3" ./run-ux.sh <brief-dir> # a subset
|
|
# MODELS="codex:gpt-6-astra" ./run-ux.sh <brief-dir> # Codex CLI lane
|
|
# TIMEOUT=3600 VARIANT=high ./run-ux.sh <brief-dir> # budget, reasoning effort
|
|
# OUT=<dir> ./run-ux.sh <brief-dir> # findings dir; default <brief-dir>/out
|
|
# EXTRA=<file> INCLUDE="<file> ..." ./run-ux.sh <brief-dir>
|
|
#
|
|
# A MODELS entry is "<harness>:<model>"; no prefix means opencode (harness.sh).
|
|
set -euo pipefail
|
|
HERE="$(cd "$(dirname "$0")" && pwd)"
|
|
REPO="$(git -C "$HERE" rev-parse --show-toplevel)"
|
|
. "$HERE/harness.sh"
|
|
BRIEF_DIR="${1:?usage: OUT=<dir> ./run-ux.sh <brief-dir>}"
|
|
BRIEF_DIR="$(cd "$BRIEF_DIR" && pwd)"
|
|
[[ -d "$HERE/.code" ]] || { echo "No $HERE/.code: run $HERE/prepare.sh first." >&2; exit 1; }
|
|
DESIGNER="${DESIGNER:-$BRIEF_DIR/DESIGNER.md}"; CONTEXT="${CONTEXT:-$BRIEF_DIR/CONTEXT.md}"
|
|
SCREENS="${SCREENS:-$BRIEF_DIR/SCREENS.md}"; BRIEF="${BRIEF:-$BRIEF_DIR/brief.md}"
|
|
for f in "$DESIGNER" "$CONTEXT" "$SCREENS" "$BRIEF"; do
|
|
[[ -f "$f" ]] || { echo "missing $f" >&2; exit 1; }
|
|
done
|
|
# Findings land where the caller says; never in this directory, which is tracked.
|
|
OUT="${OUT:-$BRIEF_DIR/out}"; mkdir -p "$OUT"; OUT="$(cd "$OUT" && pwd)"; export OUT
|
|
|
|
DEFAULT_MODELS="deepseek/deepseek-v4-pro google/gemini-3.8-flash zai-coding-plan/glm-5.3 kimi-for-coding/k3-256k"
|
|
MODELS="${MODELS:-$DEFAULT_MODELS}"
|
|
TIMEOUT="${TIMEOUT:-2700}"
|
|
VARIANT="${VARIANT-max}"
|
|
harness_check_auth $MODELS
|
|
|
|
RUN_DIR="$OUT/$(date +%Y-%m-%d_%H%M%S)"
|
|
mkdir -p "$RUN_DIR/_static"
|
|
# bootstrap.css from the snapshot; app.css from the working tree, so a mockup
|
|
# renders against the stylesheet the change is being made under.
|
|
cp "$HERE/.code/internal/embeds/static/bootstrap.css" "$REPO/internal/embeds/static/app.css" "$RUN_DIR/_static/"
|
|
|
|
# The brief travels inside the disposable copy, in a per-run directory so two
|
|
# runs with different briefs can overlap. EXTRA (a file) is appended to the
|
|
# prompt after brief.md; INCLUDE (space-separated files) travel alongside for
|
|
# the model to read, and are named at the end of the prompt.
|
|
UX="ux-$(basename "$RUN_DIR")"
|
|
mkdir -p "$HERE/.code/$UX"
|
|
cp "$DESIGNER" "$HERE/.code/$UX/DESIGNER.md"; cp "$CONTEXT" "$HERE/.code/$UX/CONTEXT.md"; cp "$SCREENS" "$HERE/.code/$UX/SCREENS.md"; cp "$BRIEF" "$HERE/.code/$UX/brief.md"
|
|
EXTRA_CAT=""; INCLUDE_LINE=""
|
|
if [[ -n "${EXTRA:-}" ]]; then cp "$EXTRA" "$HERE/.code/$UX/extra.md"; EXTRA_CAT="; echo; echo '---'; cat $UX/extra.md"; fi
|
|
if [[ -n "${INCLUDE:-}" ]]; then
|
|
mkdir -p "$HERE/.code/$UX/include"; names=""
|
|
for f in $INCLUDE; do cp "$f" "$HERE/.code/$UX/include/"; names="$names $UX/include/$(basename "$f")"; done
|
|
INCLUDE_LINE="; echo; echo 'Files to read first, in this copy:$names'"
|
|
fi
|
|
|
|
{
|
|
echo "commit $(cat "$HERE/.code/AUDIT_COMMIT.txt")"
|
|
echo "models $MODELS"
|
|
echo "brief $(basename "$BRIEF") context $(basename "$CONTEXT") screens $(basename "$SCREENS")${EXTRA:+ + extra $(basename "$EXTRA")}${INCLUDE:+ + include $INCLUDE}"
|
|
echo "variant ${VARIANT:-none}"
|
|
echo "timeout ${TIMEOUT}s per lane"
|
|
echo "started $(date -Is)"
|
|
} > "$RUN_DIR/manifest.txt"
|
|
|
|
compose() { docker compose -f "$HERE/compose.yaml" --project-directory "$HERE" "$@"; }
|
|
compose up -d egress-proxy >/dev/null
|
|
|
|
run_lane() {
|
|
local model="$1"
|
|
local harness id safe; harness="$(harness_of "$model")"; id="$(model_of "$model")"; safe="$(safe_name "$model")"
|
|
local outdir="$RUN_DIR/$safe"; mkdir -p "$outdir"
|
|
local state="$HERE/.run/$UX/$safe"; mkdir -p "$state"
|
|
local -a LANE_DOCKER=(-v "$RUN_DIR:/ux-out"); mapfile -t -O 2 LANE_DOCKER < <(harness_mount "$harness" "$state")
|
|
echo "==> [$model] started $(date +%H:%M:%S)"
|
|
# Fresh --rm container per attempt. The prompt is the four brief files plus
|
|
# one line naming this lane's output directory.
|
|
local prompt="cat $UX/DESIGNER.md; echo; echo '---'; cat $UX/CONTEXT.md; echo; echo '---'; cat $UX/SCREENS.md; echo; echo '---'; cat $UX/brief.md$EXTRA_CAT$INCLUDE_LINE; echo; echo 'Write the mockup to /ux-out/$safe/mockup.html (the directory exists; use that absolute path).'"
|
|
if ! harness_run_task "$harness" "$id" "$VARIANT" "$prompt" "$outdir/proposal.md" "$outdir/proposal.err" "$outdir/_lane.log"; then
|
|
echo "exit non-zero or timeout at $(date -Is); agent exit codes are unreliable, judge by proposal.md" >>"$outdir/_lane.log"
|
|
fi
|
|
harness_release "$harness" "$state"
|
|
if [[ -s "$outdir/proposal.md" ]] && grep -q '^COMPLETE' "$outdir/proposal.md"; then
|
|
echo " ok [$model] $(wc -l <"$outdir/proposal.md") lines; mockup: $([[ -f "$outdir/mockup.html" ]] && echo yes || echo NO)"
|
|
else
|
|
echo " SUSPECT [$model] empty or no COMPLETE line; see $outdir/proposal.err"
|
|
fi
|
|
}
|
|
|
|
pids=()
|
|
for m in $MODELS; do run_lane "$m" & pids+=("$!"); done
|
|
echo "==> ${#pids[@]} lanes running (pids ${pids[*]}); one provider per lane"
|
|
wait "${pids[@]}" || true
|
|
|
|
# The container runs as root; hand the files back to the invoking user.
|
|
compose run --rm --no-deps -T -v "$RUN_DIR:/ux-out" auditor chown -R "$(id -u):$(id -g)" /ux-out >/dev/null 2>&1 || true
|
|
echo "finished $(date -Is)" >> "$RUN_DIR/manifest.txt"
|
|
echo "Proposals under: $RUN_DIR"
|