Tailscale, Patchmon, and Semaphore sync jobs all wrote into a shared
job_runs table with no retention. With default poll intervals of 15-60
minutes, history grew unbounded.
- Add pruneJobRuns(jobId) and pruneAllJobRuns() helpers.
- Prune after every completeJobRun() so new runs trim old ones.
- Prune once on init() to clean up existing over-cap rows.
- Prune in importJobs() so re-imported runs are also capped.
- Defensive LIMIT 10 in getJobRuns() for the read path.
No UI changes needed — _renderRunList already renders whatever the
server returns. No schema migration — only row deletions.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Patchmon's API uses standard RFC 7617 Basic auth — `Basic base64(token_key:token_secret)`. The handler was sending the api_token field verbatim, so it only worked if the user had manually base64-encoded the credential. After a Patchmon upgrade, the sync started returning HTML (the SPA, served when auth is rejected) and failing with "Unexpected token '<'" on JSON.parse.
Now: if the token contains ':' (raw key:secret), encode it server-side; otherwise pass through unchanged for backward compatibility. UI gets a placeholder hint showing the expected format.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Merge the request body onto the existing instance row before validating,
so external callers (n8n, scripts) can send only the fields they want to
change instead of GET-then-splat-then-PUT the full record.
Mirrors the partial-update pattern already used by PUT /api/jobs/:id.
Full-body PUTs (today's frontend) are unaffected.
it('caps history at the last 10 runs per job',()=>{
createJob(baseJob);
constid=getJobs()[0].id;
for(leti=0;i<15;i++){
construnId=createJobRun(id);
completeJobRun(runId,'success',`run ${i}`);
}
construns=getJobRuns(id);
expect(runs).toHaveLength(10);
expect(runs[0].result).toBe('run 14');
expect(runs[9].result).toBe('run 5');
});
});
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.