Isolate IM cron tools and trust-gate read APIs.

Scope list/pause/delete to the calling chat, bind IM delivery to that peer, ignore client job ids, require trusted Host for GETs, and wrap mirrored summaries as system reminders.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-09-06 14:45:37 +08:00
parent 29d946f3dd
commit 67238d746e
7 changed files with 222 additions and 29 deletions

View file

@ -178,9 +178,11 @@ export function createHostService(options = {}) {
async function createJob(input) {
const t = now()
// Ignore client-supplied ids on create — otherwise POST/tools can overwrite.
const { id: _ignoredId, ...safeInput } = input && typeof input === 'object' ? input : {}
let created
await withState((current) => {
created = createJobRecord(input, current, t)
created = createJobRecord(safeInput, current, t)
return upsertJob(current, created)
})
return jobView(created)
@ -389,6 +391,7 @@ export function createHostService(options = {}) {
}
if (path === `${API_PREFIX}/settings` && method === 'GET') {
if (!isTrustedApiRequest(req)) return write(403, { ok: false, error: 'forbidden' })
const state = await snapshot()
write(200, { ok: true, settings: state.settings })
return
@ -403,6 +406,7 @@ export function createHostService(options = {}) {
}
if (path === `${API_PREFIX}/models` && method === 'GET') {
if (!isTrustedApiRequest(req)) return write(403, { ok: false, error: 'forbidden' })
const catalog = typeof sessionPort?.listModels === 'function'
? await sessionPort.listModels()
: { groups: [], current: null }
@ -411,6 +415,7 @@ export function createHostService(options = {}) {
}
if (path === `${API_PREFIX}/presets` && method === 'GET') {
if (!isTrustedApiRequest(req)) return write(403, { ok: false, error: 'forbidden' })
const catalog = typeof sessionPort?.listPresets === 'function'
? await sessionPort.listPresets()
: { items: [], current: null }
@ -419,6 +424,7 @@ export function createHostService(options = {}) {
}
if (path === `${API_PREFIX}/workspaces` && method === 'GET') {
if (!isTrustedApiRequest(req)) return write(403, { ok: false, error: 'forbidden' })
const workspaces = typeof sessionPort?.listWorkspaces === 'function'
? await sessionPort.listWorkspaces()
: []
@ -427,6 +433,7 @@ export function createHostService(options = {}) {
}
if (path === `${API_PREFIX}/im-catalog` && method === 'GET') {
if (!isTrustedApiRequest(req)) return write(403, { ok: false, error: 'forbidden' })
const dshIm = getDshIm()
if (!dshIm || typeof dshIm.listDeliveryCatalog !== 'function') {
write(200, {
@ -456,6 +463,7 @@ export function createHostService(options = {}) {
}
if (path === `${API_PREFIX}/jobs` && method === 'GET') {
if (!isTrustedApiRequest(req)) return write(403, { ok: false, error: 'forbidden' })
const state = await snapshot()
write(200, { ok: true, jobs: listJobs(state).map(jobView) })
return
@ -474,6 +482,7 @@ export function createHostService(options = {}) {
const jobId = decodeURIComponent(jobMatch[1])
const rest = jobMatch[2] || ''
if (method === 'GET' && !rest) {
if (!isTrustedApiRequest(req)) return write(403, { ok: false, error: 'forbidden' })
const state = await snapshot()
const job = getJob(state, jobId)
if (!job) return write(404, { ok: false, error: 'job not found' })
@ -545,6 +554,7 @@ export function createHostService(options = {}) {
}
if (path === `${API_PREFIX}/history` && method === 'GET') {
if (!isTrustedApiRequest(req)) return write(403, { ok: false, error: 'forbidden' })
const state = await snapshot()
const jobId = url.searchParams.get('jobId') || undefined
write(200, { ok: true, runs: listHistory(state, jobId).map(runView) })
@ -552,6 +562,7 @@ export function createHostService(options = {}) {
}
if (path === `${API_PREFIX}/preview` && method === 'POST') {
if (!isTrustedApiRequest(req)) return write(403, { ok: false, error: 'forbidden' })
const body = await readJsonBody(req)
const settings = (await snapshot()).settings
const schedule = validateSchedule(body.schedule || body, body.timezone || settings.timezone)
@ -561,6 +572,7 @@ export function createHostService(options = {}) {
}
if (path === `${API_PREFIX}/workspace-visible` && method === 'GET') {
if (!isTrustedApiRequest(req)) return write(403, { ok: false, error: 'forbidden' })
const state = await snapshot()
const listed = url.searchParams.getAll('id')
write(200, {
@ -601,6 +613,10 @@ export function createHostService(options = {}) {
async listJobs() {
return listJobs(await snapshot()).map(jobView)
},
async getJob(jobId) {
const job = getJob(await snapshot(), jobId)
return job ? jobView(job) : null
},
async listHistory(jobId) {
return listHistory(await snapshot(), jobId).map(runView)
},