A WordPress-inspired CMS whose entire backend is PiCloud Rhai scripts deployed with pic apply, plus a SvelteKit frontend. Built to dogfood the project tool, CLI, and SDK; exercises docs/kv/files/users, docs+queue+cron +pubsub triggers, the transactional-outbox notification chain, a docs before-interceptor, set_if CAS, SSE, per-app CORS, env overlays, and a durable Workflow (validate -> enrich || seo -> publish -> finalize) started with workflow::start and polled with workflow::run_status, visualized live with Svelte Flow. FINDINGS.md / SECURITY.md capture every gap, surprise, and security issue found (each tagged [PiCloud] vs [CMS]); the platform fixes for the actionable ones ship in the preceding commit. Also folds in the read-only `pic` allowlist entries added to .claude/settings.json during the session (fewer-permission-prompts). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
42 lines
1.6 KiB
Plaintext
42 lines
1.6 KiB
Plaintext
// GET /cms/admin/workflow/runs/:id — one run's overall + per-step status, read
|
|
// straight from the platform via workflow::run_status (F-038). Replaces the
|
|
// former app-side `wfruns` KV tracking — the SDK is app-scoped, so a run from
|
|
// another app resolves to () (404) here.
|
|
import "auth" as auth;
|
|
let g = auth::guard(ctx, ["admin", "author"]);
|
|
if !g.ok { return g.response; }
|
|
|
|
let run_id = ctx.request.params.id;
|
|
let st = workflow::run_status(run_id);
|
|
if st == () { return #{ statusCode: 404, body: #{ error: "no such run" } }; }
|
|
|
|
let engine = st.status; // pending|running|succeeded|failed
|
|
let terminal = engine == "succeeded" || engine == "failed";
|
|
|
|
// Normalize per-step status for the UI. A DAG step absent from the run — its
|
|
// `when` gate was false — shows as skipped once the run is terminal, else
|
|
// pending; the engine's "ready" (queued) also maps to pending.
|
|
let steps = #{};
|
|
for name in ["validate", "enrich", "seo", "publish", "finalize"] {
|
|
let s = st.steps[name];
|
|
if s == () {
|
|
s = if terminal { "skipped" } else { "pending" };
|
|
} else if s == "ready" {
|
|
s = "pending";
|
|
}
|
|
steps[name] = #{ status: s };
|
|
}
|
|
|
|
// CMS-level overall: "blocked" when the gate stopped publish, else mirror the
|
|
// engine's terminal state (skip != fail, so the engine itself reports
|
|
// "succeeded" even when publish was gated out — F-039).
|
|
let overall_status = if !terminal {
|
|
"running"
|
|
} else if steps.publish.status == "succeeded" {
|
|
"completed"
|
|
} else {
|
|
"blocked"
|
|
};
|
|
|
|
#{ statusCode: 200, body: #{ run_id: run_id, overall: #{ status: overall_status }, steps: steps } }
|