Refactor linear chat lead workflow into checked-in files#38
Conversation
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
|
CodeAnt AI is reviewing your PR. |
📝 WalkthroughWalkthroughReplaces runtime-generated workflow source with static workflows. Adds workflow type declarations and a ChangesWorkflow-based Linear implementation and PR creation
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Suggested labels
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning Review ran into problems🔥 ProblemsGit: Failed to clone repository. Please run the Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| files.push({ | ||
| path: filePath, | ||
| content: fs.readFileSync(path.join(repoDir, filePath)).toString('base64'), | ||
| encoding: 'base64', |
There was a problem hiding this comment.
Suggestion: Reading every changed path with fs.readFileSync follows symlinks, so a symlink committed in the repo can cause this step to read and exfiltrate arbitrary files from the runner filesystem in the PR payload. Reject symlinks (or encode link metadata instead of dereferencing) before reading file contents. [security]
Severity Level: Critical 🚨
- ❌ Linear implement workflow can exfiltrate runner filesystem via PR.
- ⚠️ Cloud PR API receives unintended sensitive file contents.Steps of Reproduction ✅
1. Trigger the Linear implementation workflow so that `delegateImplementation()` runs and
calls `ctx.workflow.run(IMPLEMENT_WORKFLOW_NAME, ...)` with repo information (see
`linear/agent.ts:95-114` and `linear/agent.ts:116-160`).
2. The `linear-chat-lead` workflow in `workflows/linear-chat-lead.ts:34-88` clones the
target GitHub repo into `REPO_DIR = './repo'` and writes `.linear-chat-base-sha` (lines
45-55), then in the `open-pr` step runs `node ${CREATE_PR_SCRIPT_PATH}
${CREATE_PR_ARGS_PATH}` (lines 76-83), invoking `workflows/linear-create-pr.cjs` with
`repoDir: './repo'` (from `openPrArgs`).
3. In the cloned repo at `./repo`, create or modify a symlink that points outside the
repository, e.g. `ln -s /etc/passwd leak` and leave it untracked or changed; Git will
surface this path via `git diff --name-only ...` and/or `git ls-files --others
--exclude-standard`, which `collectDiffPaths()` in `workflows/linear-create-pr.cjs:53-65`
uses to build the `changed` set.
4. When `linear-create-pr.cjs` executes, it iterates `changed` at
`workflows/linear-create-pr.cjs:69-75`; for each `filePath` it calls
`fs.readFileSync(path.join(repoDir, filePath)).toString('base64')` (line 73) and pushes
into `files`. For the symlink, `fs.readFileSync` follows the link and reads the target
(e.g. `/etc/passwd`), and this base64 content is then sent to
`${cloudApiUrl}/api/v1/github/pull-request` in the `files` array (lines 82-86),
exfiltrating arbitrary runner filesystem contents via the PR payload.Fix in Cursor | Fix in VSCode Claude
(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** workflows/linear-create-pr.cjs
**Line:** 71:74
**Comment:**
*Security: Reading every changed path with `fs.readFileSync` follows symlinks, so a symlink committed in the repo can cause this step to read and exfiltrate arbitrary files from the runner filesystem in the PR payload. Reject symlinks (or encode link metadata instead of dereferencing) before reading file contents.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| const response = await fetch(cloudApiUrl + '/api/v1/github/pull-request', { | ||
| method: 'POST', | ||
| headers: { authorization: 'Bearer ' + pullRequestAuthToken, 'content-type': 'application/json' }, | ||
| body: JSON.stringify({ owner, repo, branch, baseSha, baseBranch: 'main', title, body, files }), |
There was a problem hiding this comment.
Suggestion: The PR target branch is hardcoded to main, which breaks repositories that use a different default/base branch (for example master or develop) and can cause PR creation to fail or target the wrong branch. Pass the intended base branch via arguments (or discover it from the remote) instead of hardcoding it. [logic error]
Severity Level: Major ⚠️
- ❌ Linear implement workflow may fail for non-main-base repos.
- ⚠️ PRs may target wrong base branch, confusing reviewers.Steps of Reproduction ✅
1. A Linear event is handled by `handleLinearEvent()` in `linear/agent.ts:74-139`; when
the LLM classifies the intent as `"implement"`, `delegateImplementation()` is called at
`linear/agent.ts:95-114`.
2. `delegateImplementation()` computes `repo = parseRepo(issue) ?? 'AgentWorkforce/cloud'`
and then calls `workflowInputs()` to build `workflowArgs` (see `linear/agent.ts:95-105`
and `linear/agent.ts:116-160`), which includes `branch` and `openPrArgs` for an arbitrary
repo derived from `issue` metadata.
3. The `linear-chat-lead` workflow in `workflows/linear-chat-lead.ts:34-88` uses these
`openPrArgs` and in its `open-pr` step (lines 76-83) runs `node
./workflows/linear-create-pr.cjs /tmp/linear-chat-lead-open-pr.args.json`, passing
`owner`, `repo`, `branch`, etc. read from JSON (see
`workflows/linear-create-pr.cjs:8-14`).
4. Inside `workflows/linear-create-pr.cjs`, after collecting diffs, the script POSTs to
`${cloudApiUrl}/api/v1/github/pull-request` with `baseBranch: 'main'` hardcoded in the
body at line 85; when the workflow is configured to operate on a repo whose primary branch
is `master`, `develop`, or any non-`main` branch, the remote API will receive an incorrect
`baseBranch` value, causing PR creation to either fail or target the wrong base branch,
breaking the Linear implementation flow for such repositories.Fix in Cursor | Fix in VSCode Claude
(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** workflows/linear-create-pr.cjs
**Line:** 85:85
**Comment:**
*Logic Error: The PR target branch is hardcoded to `main`, which breaks repositories that use a different default/base branch (for example `master` or `develop`) and can cause PR creation to fail or target the wrong branch. Pass the intended base branch via arguments (or discover it from the remote) instead of hardcoding it.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| const CREATE_PR_ARGS_PATH = `/tmp/${WORKFLOW_NAME}-open-pr.args.json`; | ||
| const CREATE_PR_SCRIPT_PATH = fileURLToPath(new URL('./linear-create-pr.cjs', import.meta.url)); | ||
|
|
||
| type OpenPrArgs = { | ||
| repoDir: string; | ||
| owner: string; | ||
| repo: string; | ||
| branch: string; | ||
| title: string; | ||
| body: string; | ||
| }; | ||
|
|
||
| type ImplementWorkflowArgs = { | ||
| repo: string; | ||
| repoOwner: string; | ||
| repoName: string; | ||
| branch: string; | ||
| issueTitle: string; | ||
| issueBody: string; | ||
| userPrompt: string; | ||
| issueId?: string; | ||
| issueIdentifier?: string; | ||
| issueUrl?: string; | ||
| openPrArgs: OpenPrArgs; | ||
| }; | ||
|
|
||
| const args = readInvocationArgs(); | ||
|
|
||
| await workflow(WORKFLOW_NAME) | ||
| .description('Implement a Linear issue delegated by the chat lead') | ||
| .pattern('dag') | ||
| .timeout(4_500_000) | ||
| .agent('impl', { | ||
| cli: 'codex', | ||
| preset: 'worker', | ||
| role: 'Implement the Linear issue and prepare a PR.', | ||
| retries: 1, | ||
| maxTokens: 32000, | ||
| }) | ||
| .step('clone', { | ||
| type: 'deterministic', | ||
| command: [ | ||
| 'set -e', | ||
| `rm -rf ${shellArg(REPO_DIR)}`, | ||
| `git clone --filter=blob:none ${shellArg(`https://github.com/${args.repo}.git`)} ${shellArg(REPO_DIR)}`, | ||
| `cd ${shellArg(REPO_DIR)} && git checkout -B ${shellArg(args.branch)}`, | ||
| `cd ${shellArg(REPO_DIR)} && git config user.email ${shellArg('linear-chat-lead@agentworkforce.local')}`, | ||
| `cd ${shellArg(REPO_DIR)} && git config user.name ${shellArg('linear-chat-lead')}`, | ||
| `cd ${shellArg(REPO_DIR)} && git rev-parse HEAD > .linear-chat-base-sha`, | ||
| ].join(' && '), | ||
| captureOutput: true, | ||
| failOnError: true, | ||
| timeoutMs: 900000, | ||
| }) | ||
| .step('implement', { | ||
| agent: 'impl', | ||
| dependsOn: ['clone'], | ||
| task: [ | ||
| `Work in ${REPO_DIR} on branch ${args.branch}.`, | ||
| `Linear issue: ${args.issueIdentifier ? `${args.issueIdentifier}: ` : ''}${args.issueTitle}`, | ||
| args.issueUrl ? `Issue URL: ${args.issueUrl}` : '', | ||
| `User prompt: ${args.userPrompt || '(no explicit prompt)'}`, | ||
| `Issue body:\n${args.issueBody}`, | ||
| 'Make the code changes needed to fully satisfy the Linear request.', | ||
| 'Do not commit, push, or open a PR; the final deterministic step handles that.', | ||
| ].filter(Boolean).join('\n\n'), | ||
| verification: { type: 'exit_code', value: '0' }, | ||
| timeoutMs: 1_800_000, | ||
| retries: 1, | ||
| }) | ||
| .step('open-pr', { | ||
| type: 'deterministic', | ||
| dependsOn: ['implement'], | ||
| command: [ | ||
| 'set -e', | ||
| `printf %s ${shellArg(JSON.stringify(args.openPrArgs, null, 2))} > ${shellArg(CREATE_PR_ARGS_PATH)}`, | ||
| `node ${shellArg(CREATE_PR_SCRIPT_PATH)} ${shellArg(CREATE_PR_ARGS_PATH)}`, |
There was a problem hiding this comment.
Suggestion: The workflow writes PR arguments to a fixed global path in /tmp, so concurrent runs of the same workflow can overwrite each other's args file before the node step reads it. This can cause one run to open a PR with another run's data. Use a per-run unique temp file path (for example, include a run id or random suffix) to avoid cross-run collisions. [race condition]
Severity Level: Critical 🚨
- ❌ Linear implement runs can open PRs with wrong metadata.
- ⚠️ GitHub PRs may reference incorrect branch or repository.Steps of Reproduction ✅
1. A Linear event with intent "implement" is received and handled by the default agent in
`linear/agent.ts:51-72`, which calls `handleLinearEvent()` at `linear/agent.ts:74-139`.
2. For "implement" intent, `delegateImplementation()` at `linear/agent.ts:234-253`
constructs workflow args via `workflowInputs()` (`linear/agent.ts:255-261`) and calls
`ctx.workflow.run('linear-chat-lead', ...)` at `linear/agent.ts:245`, starting a
`linear-chat-lead` workflow run.
3. Each workflow run executes the `open-pr` step defined in
`workflows/linear-chat-lead.ts:76-87`, which writes PR arguments to the fixed path
`CREATE_PR_ARGS_PATH = "/tmp/linear-chat-lead-open-pr.args.json"` at
`workflows/linear-chat-lead.ts:6` via the shell command at
`workflows/linear-chat-lead.ts:81` and then invokes `node linear-create-pr.cjs
/tmp/linear-chat-lead-open-pr.args.json` at `workflows/linear-chat-lead.ts:82`.
4. Trigger two implementation flows close together (e.g., two Linear issues both
classified as "implement") so the workflow engine runs two `linear-chat-lead` workflows
concurrently on the same worker host; when both reach the `open-pr` step, one run's
`printf` at `workflows/linear-chat-lead.ts:81` can overwrite
`/tmp/linear-chat-lead-open-pr.args.json` between the other run's `printf` and the
`fs.readFileSync(argsPath, 'utf8')` in `workflows/linear-create-pr.cjs:8`, causing the
first run's `linear-create-pr.cjs` process to read the second run's PR arguments and open
a PR with mismatched metadata (owner/repo/branch from another run, see
`workflows/linear-create-pr.cjs:9-14`).Fix in Cursor | Fix in VSCode Claude
(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** workflows/linear-chat-lead.ts
**Line:** 6:82
**Comment:**
*Race Condition: The workflow writes PR arguments to a fixed global path in `/tmp`, so concurrent runs of the same workflow can overwrite each other's args file before the `node` step reads it. This can cause one run to open a PR with another run's data. Use a per-run unique temp file path (for example, include a run id or random suffix) to avoid cross-run collisions.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix|
CodeAnt AI finished reviewing your PR. |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@workflows/linear-chat-lead.ts`:
- Around line 6-7: The current CREATE_PR_ARGS_PATH constant uses a fixed /tmp
path which allows concurrent workflow runs to clobber each other's payloads;
replace the single constant with a per-run computed path (e.g., include
process.pid, Date.now(), or crypto.randomUUID()) and update all usages that
write/read the args file (where CREATE_PR_ARGS_PATH is referenced and where
CREATE_PR_SCRIPT_PATH is invoked) to use this per-run path; ensure the writer
that serializes the PR args and the child script invocation both use the same
generated filename and optionally unlink the temp file after the script
completes.
In `@workflows/linear-create-pr.cjs`:
- Around line 69-75: The current loop reads file contents using
fs.readFileSync(path.join(repoDir, filePath)) which follows symlinks and can
leak host files; before reading, use fs.lstatSync(path.join(repoDir, filePath))
to detect symbolic links (fs.Stats.isSymbolicLink()), and if a symlink is found
either skip the entry or resolve the link with fs.readlinkSync and path.resolve
then verify the resolved target starts with the repoDir path; only read and push
content into files when the target is inside repoDir. Refer to the
variables/file names filePath, repoDir, files, and the push block where
fs.readFileSync is called to implement this check and reject or ignore external
symlink targets.
- Line 85: The PR payload currently hardcodes baseBranch: 'main' in the JSON
body (see the JSON.stringify call that includes owner, repo, branch, baseSha,
baseBranch), which breaks repos with non-main default branches; update the code
to derive baseBranch from the cloned repository or the repo metadata (e.g., read
the repo's default branch via git remote/branch lookup or the repo API) and pass
that variable (e.g., defaultBranch or derivedBaseBranch) instead of the string
'main' when building the body for PR creation so baseSha and baseBranch remain
consistent.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 57d9de7a-132c-42de-baf8-eb6102661e7b
📒 Files selected for processing (7)
linear/agent.tslinear/create-pr.script.tstests/linear-agent.test.mjstsconfig.jsonworkflows/agent-relay-workflows.d.tsworkflows/linear-chat-lead.tsworkflows/linear-create-pr.cjs
💤 Files with no reviewable changes (1)
- linear/create-pr.script.ts
There was a problem hiding this comment.
4 issues found across 7 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
|
CodeAnt AI is running Incremental review |
|
CodeAnt AI Incremental review completed. |
There was a problem hiding this comment.
1 issue found across 4 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="workflows/linear-create-pr.cjs">
<violation number="1" location="workflows/linear-create-pr.cjs:68">
P1: Fallback base-branch detection can pick `origin/HEAD -> ...` as a branch name, producing an invalid `baseBranch` like `HEAD -> origin/main` in PR creation requests.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| if (remoteHeadMatch) return remoteHeadMatch[1]; | ||
| const branchAtBase = gitLinesOrEmpty(['branch', '-r', '--points-at', baseSha]) | ||
| .map((line) => line.trim()) | ||
| .find((line) => line.startsWith('origin/') && line !== 'origin/HEAD'); |
There was a problem hiding this comment.
P1: Fallback base-branch detection can pick origin/HEAD -> ... as a branch name, producing an invalid baseBranch like HEAD -> origin/main in PR creation requests.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At workflows/linear-create-pr.cjs, line 68:
<comment>Fallback base-branch detection can pick `origin/HEAD -> ...` as a branch name, producing an invalid `baseBranch` like `HEAD -> origin/main` in PR creation requests.</comment>
<file context>
@@ -50,6 +59,17 @@
+ if (remoteHeadMatch) return remoteHeadMatch[1];
+ const branchAtBase = gitLinesOrEmpty(['branch', '-r', '--points-at', baseSha])
+ .map((line) => line.trim())
+ .find((line) => line.startsWith('origin/') && line !== 'origin/HEAD');
+ if (branchAtBase) return branchAtBase.replace(/^origin\//, '');
+ return 'main';
</file context>
| .find((line) => line.startsWith('origin/') && line !== 'origin/HEAD'); | |
| .find((line) => /^origin\/[^\s]+$/.test(line) && !line.startsWith('origin/HEAD')); |
|
Fixed a runtime break in PR #38: the checked-in workflow was referencing Changes made:
Verification run locally:
|
|
CodeAnt AI is running Incremental review |
|
✅ pr-reviewer applied fixes — committed and pushed Fixed a runtime break in PR #38: the checked-in workflow was referencing Changes made:
Verification run locally:
|
|
CodeAnt AI Incremental review completed. |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
workflows/linear-chat-lead.ts (1)
177-186:⚠️ Potential issue | 🟠 Major | ⚡ Quick winCollapse the duplicated repo/branch/repoDir contract.
The workflow clones
args.repointoREPO_DIRonargs.branch, butopen-prreads an independentopenPrArgs.repoDir/repo/branch. A mismatched caller payload will publish the wrong tree or target the wrong PR branch. Derive these fields from the workflow’s canonical values, or at least reject mismatches duringreadInvocationArgs().Suggested guard
function readInvocationArgs(): ImplementWorkflowArgs { const raw = process.env.invocationArgs ?? '{}'; const parsed = parseJsonObject(raw, 'invocationArgs'); const openPrArgs = readObject(parsed.openPrArgs, 'openPrArgs'); + const repo = readRequiredString(parsed, 'repo'); + const branch = readRequiredString(parsed, 'branch'); + const prRepoDir = readRequiredString(openPrArgs, 'repoDir'); + const prOwner = readRequiredString(openPrArgs, 'owner'); + const prRepo = readRequiredString(openPrArgs, 'repo'); + const prBranch = readRequiredString(openPrArgs, 'branch'); + + if (prRepoDir !== REPO_DIR) { + throw new Error(`invocationArgs.openPrArgs.repoDir must be ${REPO_DIR}`); + } + if (`${prOwner}/${prRepo}` !== repo) { + throw new Error('invocationArgs.openPrArgs owner/repo must match invocationArgs.repo'); + } + if (prBranch !== branch) { + throw new Error('invocationArgs.openPrArgs.branch must match invocationArgs.branch'); + } + return { - repo: readRequiredString(parsed, 'repo'), - branch: readRequiredString(parsed, 'branch'), + repo, + branch, issueTitle: readRequiredString(parsed, 'issueTitle'), issueBody: readString(parsed.issueBody), userPrompt: readString(parsed.userPrompt), @@ openPrArgs: { - repoDir: readRequiredString(openPrArgs, 'repoDir'), - owner: readRequiredString(openPrArgs, 'owner'), - repo: readRequiredString(openPrArgs, 'repo'), - branch: readRequiredString(openPrArgs, 'branch'), + repoDir: prRepoDir, + owner: prOwner, + repo: prRepo, + branch: prBranch, title: readRequiredString(openPrArgs, 'title'), body: readRequiredString(openPrArgs, 'body'), },Also applies to: 229-246
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@workflows/linear-chat-lead.ts` around lines 177 - 186, The workflow currently duplicates repository/branch/dir across the clone step and the open-pr payload (see step 'clone' using args.repo, args.branch, REPO_DIR and the open-pr handler reading openPrArgs.repoDir/repo/branch), which can cause mismatched publishes; update readInvocationArgs() (or the open-pr handler) to either derive openPrArgs.repo/openPrArgs.branch/openPrArgs.repoDir from the canonical workflow values (args.repo, args.branch, REPO_DIR) or validate and reject any invocation where openPrArgs.* differs from those canonical values—implement a clear check that compares openPrArgs.repo === args.repo && openPrArgs.branch === args.branch && openPrArgs.repoDir === REPO_DIR and throw/return an error if not, so the clone and open-pr cannot drift.
♻️ Duplicate comments (1)
workflows/linear-chat-lead.ts (1)
6-7:⚠️ Potential issue | 🟠 Major | ⚡ Quick winGenerate the temp file paths inside the step, not at module load.
This is still process-global state. If the workflow runtime reuses the loaded module across invocations, overlapping runs will share the same
script_path/args_pathand can overwrite each other's PR payloads. Create both paths inside theopen-prcommand (mktempor equivalent) so each execution gets fresh files.Suggested fix
-import { randomUUID } from 'node:crypto'; @@ -const createPrScriptPath = `/tmp/${WORKFLOW_NAME}-create-pr-${randomUUID()}.cjs`; -const createPrArgsPath = `/tmp/${WORKFLOW_NAME}-open-pr-${randomUUID()}.args.json`; @@ - `script_path=${shellArg(createPrScriptPath)}`, - `args_path=${shellArg(createPrArgsPath)}`, + `script_path=$(mktemp /tmp/${WORKFLOW_NAME}-create-pr.XXXXXX.cjs)`, + `args_path=$(mktemp /tmp/${WORKFLOW_NAME}-open-pr.XXXXXX.args.json)`, 'trap \'rm -f "$args_path" "$script_path"\' EXIT',Also applies to: 213-218
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@workflows/linear-chat-lead.ts` around lines 6 - 7, The temp file paths createPrScriptPath and createPrArgsPath are generated at module load, creating process-global state that can collide across concurrent workflow invocations; move the creation of these temp paths into the execution scope of the "open-pr" step/command (e.g., inside the function that builds/runs the open-pr command or the step handler), using a per-run temp generator (mktemp or randomUUID() called at runtime) so each invocation gets fresh script and args files; update any references to createPrScriptPath/createPrArgsPath to use the locally generated variables and remove the module-level globals.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@workflows/linear-chat-lead.ts`:
- Around line 177-186: The workflow currently duplicates repository/branch/dir
across the clone step and the open-pr payload (see step 'clone' using args.repo,
args.branch, REPO_DIR and the open-pr handler reading
openPrArgs.repoDir/repo/branch), which can cause mismatched publishes; update
readInvocationArgs() (or the open-pr handler) to either derive
openPrArgs.repo/openPrArgs.branch/openPrArgs.repoDir from the canonical workflow
values (args.repo, args.branch, REPO_DIR) or validate and reject any invocation
where openPrArgs.* differs from those canonical values—implement a clear check
that compares openPrArgs.repo === args.repo && openPrArgs.branch === args.branch
&& openPrArgs.repoDir === REPO_DIR and throw/return an error if not, so the
clone and open-pr cannot drift.
---
Duplicate comments:
In `@workflows/linear-chat-lead.ts`:
- Around line 6-7: The temp file paths createPrScriptPath and createPrArgsPath
are generated at module load, creating process-global state that can collide
across concurrent workflow invocations; move the creation of these temp paths
into the execution scope of the "open-pr" step/command (e.g., inside the
function that builds/runs the open-pr command or the step handler), using a
per-run temp generator (mktemp or randomUUID() called at runtime) so each
invocation gets fresh script and args files; update any references to
createPrScriptPath/createPrArgsPath to use the locally generated variables and
remove the module-level globals.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: cc5cdafb-c2f2-4557-9e75-6d566892b6e9
📒 Files selected for processing (4)
linear/agent.tstests/linear-agent.test.mjsworkflows/linear-chat-lead.tsworkflows/linear-create-pr.cjs
💤 Files with no reviewable changes (1)
- linear/agent.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- workflows/linear-create-pr.cjs
User description
Summary
Verification
Summary by cubic
Refactored the Linear chat lead to use checked-in workflow and PR helper files, removing inline base64 scripts and runtime file writes for better security and reliability. The user flow is unchanged.
workflows/linear-chat-lead.tsthat readsprocess.env.invocationArgs, clones the repo, delegates work, and writes a UUID-based temp helper script and JSON args (withtrapcleanup) before running it via@agent-relay/sdk/workflows.workflows/linear-create-pr.cjsto open PRs from JSON args; auto-detectsbaseBranchfromorigin/HEADor the base SHA, rejects symlinks and paths outside the repo, and posts to/api/v1/github/pull-requestusingWORKFORCE_WORKSPACE_TOKENorCLOUD_API_ACCESS_TOKEN.linear/create-pr.script.ts; simplifiedlinear/agent.tsto pass structured args toctx.workflow.run('linear-chat-lead', ...).workflows/agent-relay-workflows.d.tsand updatedtsconfig.jsonto include workflow files; updated tests to cover structured invocation args, no base64 embedding, safety checks, and base-branch detection.Written for commit 2870977. Summary will update on new commits.
CodeAnt-AI Description
Move the Linear chat lead workflow and PR helper into checked-in files
What Changed
Impact
✅ Safer PR creation from agent-generated changes✅ Fewer runtime workflow failures✅ Correct PRs when the base branch is not main💡 Usage Guide
Checking Your Pull Request
Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.
Talking to CodeAnt AI
Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:
This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.
Example
Preserve Org Learnings with CodeAnt
You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:
This helps CodeAnt AI learn and adapt to your team's coding style and standards.
Example
Retrigger review
Ask CodeAnt AI to review the PR again, by typing:
Check Your Repository Health
To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.