Jason asked for tasks.mosaicstack.dev operational with agents configured in it. Sage backed it up, tested the restore, pinned 2.7.0 (infra PR #325) and ran sections 2 and 3 through the API: owner id 4, svc-mosaic-stack id 5, project 32, bots 6-10, scoped tokens to 2027-01-07. Probes pass. Scope is Mosaic Stack only (Mos relaying Jason, his Q9 open). OIDC has been broken since a 2026-04-27 NetworkPolicy; infra PR #326 is with ops-01. BUILD-LOG also records the cert renewal fix and the last-applied annotation slip. Co-Authored-By: Claude Opus 5.5 <[email protected]>
36 lines
2.2 KiB
JavaScript
36 lines
2.2 KiB
JavaScript
// Sage, 2026-10-09: task round trip for the mosaic-stack bots on tasks.mosaicstack.dev, then cleanup as the owner.
|
|
// Prints statuses and ids only. Usage: node roundtrip.mjs SECRETS_DIR PROJECT_ID FOREIGN_TASK_ID
|
|
import { readFileSync } from "node:fs";
|
|
const [S, P, FOREIGN] = process.argv.slice(2);
|
|
const BASE = "https://tasks.mosaicstack.dev/api/v2";
|
|
const rd = (f) => readFileSync(`${S}/${f}`, "utf8").trim();
|
|
async function call(method, path, tok, body) {
|
|
const headers = { Authorization: `Bearer ${tok}`, "Content-Type": "application/json" };
|
|
const r = await fetch(BASE + path, { method, headers, body: body === undefined ? undefined : JSON.stringify(body) });
|
|
let j = null; try { j = await r.json(); } catch {}
|
|
return { s: r.status, j };
|
|
}
|
|
const login = await fetch(BASE + "/login", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ username: "mosaic-stack-owner", password: rd("vikunja-owner.password") }) });
|
|
const owner = (await login.json()).token;
|
|
const pm = rd("pm-vikunja.token");
|
|
const made = await call("POST", `/projects/${P}/tasks`, pm, { title: "probe: delete me (sage 2026-10-09)" });
|
|
console.log("pm create", made.s, made.j?.id, "bucket", made.j?.bucket_id);
|
|
const T = made.j?.id;
|
|
for (const r of ["cto", "coder", "reviewer"]) {
|
|
const tok = rd(`${r}-vikunja.token`);
|
|
const read = await call("GET", `/tasks/${T}`, tok);
|
|
const cmt = await call("POST", `/tasks/${T}/comments`, tok, { comment: `probe comment from ${r}` });
|
|
const foreign = await call("GET", `/tasks/${FOREIGN}`, tok);
|
|
const del = await call("DELETE", `/tasks/${T}`, tok);
|
|
console.log(r, `read=${read.s}`, `comment=${cmt.s}`, `foreignTask=${foreign.s}`, `delete=${del.s}`);
|
|
}
|
|
const sync = rd("sync-vikunja.token");
|
|
const sread = await call("GET", `/tasks/${T}`, sync);
|
|
const swrite = await call("POST", `/tasks/${T}/comments`, sync, { comment: "sync should not write" });
|
|
const sforeign = await call("GET", `/tasks/${FOREIGN}`, sync);
|
|
console.log("sync", `read=${sread.s}`, `comment=${swrite.s}`, `foreignTask=${sforeign.s}`);
|
|
const pforeign = await call("GET", `/tasks/${FOREIGN}`, pm);
|
|
console.log("pm", `foreignTask=${pforeign.s}`);
|
|
const gone = await call("DELETE", `/tasks/${T}`, owner);
|
|
console.log("owner cleanup delete", gone.s);
|