fix: P2 bugs - heartbeat timing, symlink check, conflict detection
worker.nim: - Start heartbeat before state transition in start command (prevents WORKING state without heartbeat if startup fails) context.nim: - Reject symlinks when reading context file (security) (prevents reading arbitrary files via symlinked .worker-ctx.json) git.nim: - Use case-insensitive conflict detection in rebase/merge (toLowerAscii instead of checking "CONFLICT" and "conflict" separately) Closes: skills-qekj, skills-16zf, skills-n3qp Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
c44f2106ee
commit
3afd621bb4
|
|
@ -204,10 +204,10 @@ proc start(task: string = "") =
|
|||
echo "Already WORKING: ", taskId
|
||||
quit(ExitSuccess)
|
||||
|
||||
db.transition(taskId, wsAssigned, wsWorking)
|
||||
|
||||
# Start heartbeat
|
||||
# Start heartbeat before transition so we're heartbeating when state changes
|
||||
startGlobalHeartbeat(BusDbPath, taskId)
|
||||
|
||||
db.transition(taskId, wsAssigned, wsWorking)
|
||||
updateGlobalHeartbeat(hsWorking, taskId)
|
||||
|
||||
echo "Started work on ", taskId
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@ proc readContext*(worktree: string = ""): WorkerContext =
|
|||
if not fileExists(path):
|
||||
raise newException(IOError, &"Context file not found: {path}")
|
||||
|
||||
# Security: reject symlinks to prevent reading arbitrary files
|
||||
if getFileInfo(path).kind == pcLinkToFile:
|
||||
raise newException(IOError, &"Context file is a symlink (rejected): {path}")
|
||||
|
||||
try:
|
||||
let content = readFile(path)
|
||||
let j = parseJson(content)
|
||||
|
|
@ -38,6 +42,9 @@ proc findContext*(): WorkerContext =
|
|||
while dir != "" and dir != "/":
|
||||
let path = dir / ContextFileName
|
||||
if fileExists(path):
|
||||
# Security: reject symlinks to prevent reading arbitrary files
|
||||
if getFileInfo(path).kind == pcLinkToFile:
|
||||
raise newException(IOError, &"Context file is a symlink (rejected): {path}")
|
||||
try:
|
||||
let content = readFile(path)
|
||||
let j = parseJson(content)
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ proc rebaseOnIntegration*(worktree: string): bool =
|
|||
let (output, code) = runGit("rebase", "origin/integration", workDir = worktree)
|
||||
|
||||
if code != 0:
|
||||
if "CONFLICT" in output or "conflict" in output:
|
||||
if "conflict" in output.toLowerAscii():
|
||||
return false
|
||||
# Other error - abort and raise
|
||||
discard runGit("rebase", "--abort", workDir = worktree)
|
||||
|
|
@ -111,7 +111,7 @@ proc mergeToIntegration*(taskId: string, maxRetries: int = 3): bool =
|
|||
let (mergeOutput, mergeCode) = runGit("merge", "--no-ff", branch,
|
||||
"-m", &"Merge {branch}")
|
||||
if mergeCode != 0:
|
||||
if "CONFLICT" in mergeOutput:
|
||||
if "conflict" in mergeOutput.toLowerAscii():
|
||||
discard runGit("merge", "--abort")
|
||||
return false
|
||||
raise newException(GitError, &"Merge failed: {mergeOutput}")
|
||||
|
|
|
|||
Loading…
Reference in a new issue