ci: consolidate Gemini + quota-gate + Jules workflows onto master-staging - #75
Conversation
|
Mention Blocks like a regular teammate with your question or request: @blocks review this pull request Run |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
@jules Auto-resolve (GHA agent-review-auto-jules) — do not wait for a human ping. Feedback excerptInstructions
|
|
Warning Review limit reached
Next review available in: 35 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughAdds quota-gated Gemini workflows, Jules issue automation, wiki publishing, and offline connector smoke checks. The workflows validate requests, coordinate related agent work, select API keys, and route tasks to reusable workflows. ChangesGemini automation
Jules issue automation
Connector smoke checks
Wiki publishing
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant GitHubEvent
participant GeminiDispatch
participant QuotaGate
participant GeminiWorkflow
participant GeminiCLI
GitHubEvent->>GeminiDispatch: submit supported command
GeminiDispatch->>GeminiDispatch: validate request and collect related PRs
GeminiDispatch->>QuotaGate: check daily quota
QuotaGate-->>GeminiWorkflow: skip or selected API key
GeminiWorkflow->>GeminiCLI: run task with repository context
Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
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 |
ADE status — consolidation complete for core Gemini stackBranch: On this PR now
Optional follow-ups (can land after)
Why not merge #72#72 is dirty (79 files, conflicts). This PR is workflows-only. Merge sequence (when gates green)
Test after promote to masterDo not merge yet until repo-gate + termux-smoke pass on this PR. Signed-off-by: Grok (ADE) |
| pr-number: ${{ github.event.pull_request.number || '' }} | ||
| command: 'review' | ||
| has-backup-key: ${{ secrets.GEMINI_API_KEY_BACKUP != '' }} | ||
|
|
||
| - name: Run Gemini CLI PR review | ||
| if: | | ||
| steps.session.outputs.already_reviewed != 'true' && | ||
| steps.quota.outputs.skip != 'true' | ||
| uses: google-github-actions/run-gemini-cli@v0 | ||
| env: | ||
| GEMINI_CLI_TRUST_WORKSPACE: 'true' | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| with: | ||
| gemini_api_key: ${{ steps.quota.outputs.use_backup_key == 'true' && secrets.GEMINI_API_KEY_BACKUP || secrets.GEMINI_API_KEY }} | ||
| github_pr_number: ${{ github.event.pull_request.number }} |
There was a problem hiding this comment.
🔴 Requested pull-request reviews are silently skipped once any earlier review exists
When a review is requested by comment, the workflow compares past review notes against an empty commit identifier (c.body?.includes(headSha) at .github/workflows/gemini-review.yml:64), which always matches, so it concludes the code was already reviewed and does nothing.
Impact: Typing @gemini-cli /review on a pull request that has ever been reviewed before produces no review at all, with no visible error.
Mechanism: empty headSha makes String.includes always true
For comment-triggered runs (issue_comment, pull_request_review*) the dispatch workflow calls this reusable workflow, and context.payload.pull_request is undefined, so headSha is '' (.github/workflows/gemini-review.yml:48). String.prototype.includes('') returns true for any string, so the filter at :62-65 reduces to "any comment containing <!-- gemini-review-sha:", setting already_reviewed=true and short-circuiting both the quota gate (:106) and the review step (:115-117).
Secondarily, when the review does run in this path, reviewed_sha is '' (:96), so the trailing marker written by the model is <!-- gemini-review-sha: -->, which then poisons subsequent comparisons.
Fix: skip the already-reviewed check entirely when headSha is empty, and/or fetch the PR head SHA via github.rest.pulls.get using prNumber when the payload lacks a pull_request object.
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
Kimi Code: Rate limit or quota exceeded. Please wait before trying again.
Details
error: failed to run prompt: provider.rate_limit: 429 Your account org-da892ad7697f4eaeb9d8f03819ab836d is suspended due to insufficient balance, please recharge your account or check your plan and billing detailsSee log: /home/user/.kimi-code/logs/kimi-code.log
| - Minimal-diff preference | ||
| - Overlap with other open agent PRs: ${{ inputs.prior_prs }} | ||
|
|
||
| ${{ steps.session.outputs.changed_files != '' && format('## Changed files since last review\nFocus here:\n{0}', steps.session.outputs.changed_files) || '## Full review (first pass)' }} |
There was a problem hiding this comment.
📝 Info: Escaped newlines in format() render literally in the prompt
In a GitHub Actions expression, a single-quoted string literal does not interpret \n as a newline, so the generated prompt contains the literal characters \n instead of line breaks. Cosmetic only (the model will likely still parse it), but if readable prompt formatting matters, use a real multi-line YAML expression or a pre-computed step output.
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
Kimi Code: Rate limit or quota exceeded. Please wait before trying again.
Details
error: failed to run prompt: provider.rate_limit: 429 Your account org-da892ad7697f4eaeb9d8f03819ab836d is suspended due to insufficient balance, please recharge your account or check your plan and billing detailsSee log: /home/user/.kimi-code/logs/kimi-code.log
| push: | ||
| branches: [master, master-staging] | ||
| paths: | ||
| - "wiki/**" | ||
| - ".github/workflows/publish-wiki.yml" |
There was a problem hiding this comment.
🔍 No wiki/ directory exists in the repo yet
The repository currently has no top-level wiki/ directory, so the path filter wiki/** will never fire on push; only workflow_dispatch can trigger this. In that case Andrew-Chen-Wang/github-wiki-action is pointed at a non-existent path: wiki, whose behavior (no-op vs. wiping the wiki vs. error) should be verified before relying on it. Also note that including master-staging in the trigger branches means unreviewed staging content can be published to the public wiki, and both branches share one concurrency group so whichever pushes last wins.
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
The wiki is supposed to be here: https://github.com/timerloggedout-spec/termux-monorepo/wiki
From DeepWiki import or 'symlink' etc...
| else | ||
| NEW=$(( CURRENT + 1 )) | ||
| echo "$NEW" > "$COUNTER_FILE" | ||
| echo "skip=false" >> "$GITHUB_OUTPUT" | ||
| echo "remaining=$(( LIMIT - NEW ))" >> "$GITHUB_OUTPUT" | ||
| echo "use_backup_key=false" >> "$GITHUB_OUTPUT" | ||
| fi |
There was a problem hiding this comment.
📝 Info: Quota counter is subject to lost updates across concurrent runs
The daily counter is restored from a shared cache, incremented locally, and saved under a run-unique key (.github/actions/gemini-quota-gate/action.yml:49-56 and :119-125). Two workflow runs that start close together both restore the same value and both write CURRENT+1, so concurrent Gemini invocations are undercounted. Also, the exact key (gemini-quota-<date>) is never written — restoration always relies on prefix matching via restore-keys, which returns the most recently created matching cache; this works but means every run creates a new cache entry, so the day's entries compete for the repo cache eviction budget. Given the 900/day safety margin the drift is probably tolerable, but it is worth knowing the gate is best-effort rather than exact.
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
Kimi Code: Rate limit or quota exceeded. Please wait before trying again.
Details
error: failed to run prompt: provider.rate_limit: 429 Your account org-da892ad7697f4eaeb9d8f03819ab836d is suspended due to insufficient balance, please recharge your account or check your plan and billing detailsSee log: /home/user/.kimi-code/logs/kimi-code.log
| const reviewComments = comments.filter(c => | ||
| c.body?.includes('<!-- gemini-review-sha:') && | ||
| c.body?.includes(headSha) | ||
| ); |
There was a problem hiding this comment.
📝 Info: Session-continuation SHA match can false-positive on unrelated comment text
The already-reviewed check accepts any comment that contains both the marker prefix and the head SHA anywhere in the body, rather than matching the marker's captured SHA. A comment that quotes a different SHA plus the marker (e.g. a re-posted review) could wrongly suppress a review. Matching body.match(/<!-- gemini-review-sha: ([a-f0-9]+) -->/)?.[1] === headSha would be tighter. Also, since reviewed_sha is injected into the prompt for the model to echo back, a model that omits the marker means the same SHA is reviewed again on the next trigger.
Was this helpful? React with 👍 or 👎 to provide feedback.
| const { data: prs } = await github.rest.pulls.list({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| state: 'open', | ||
| per_page: 40, | ||
| }); | ||
| const agentHints = ['jules', 'devin', 'coderabbit', 'ecc-tools', 'gemini']; | ||
| const relevant = prs.filter(p => { | ||
| const u = ((p.user && p.user.login) || '').toLowerCase(); | ||
| const body = ((p.body || '') + ' ' + (p.title || '')).toLowerCase(); | ||
| return agentHints.some(a => u.includes(a)) || | ||
| (issueNum && (body.includes('#' + issueNum) || body.includes('issue ' + issueNum))); | ||
| }).slice(0, 12); |
There was a problem hiding this comment.
📝 Info: Prior-PR inventory only scans the first page of open PRs
pulls.list is capped at per_page: 40 with no pagination, so on a repo with more than 40 open PRs the agent-coordination inventory silently misses relevant PRs, weakening the "do not overlap files" guidance passed into every prompt. Consider github.paginate or filtering server-side.
Was this helpful? React with 👍 or 👎 to provide feedback.
| github.event.sender.type == 'User' && | ||
| startsWith(github.event.comment.body || github.event.review.body || '', '@gemini-cli') && | ||
| contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association || github.event.review.author_association || github.event.issue.author_association) |
There was a problem hiding this comment.
🔍 Dispatch gate relies on comment/review payload fields for non-comment events
The third clause of the job condition reads github.event.comment.body || github.event.review.body and the corresponding author associations. For pull_request_review.submitted the comment object is absent (evaluates to null in Actions expressions, so the fallback works), but note that github.event.issue.author_association is used as the last fallback for association — that reflects who opened the issue, not who commented, so on an issue opened by a maintainer any user comment starting with @gemini-cli would pass the association check if comment.author_association were ever empty. In practice comment.author_association is always populated on issue_comment events, so this is defensive-only, but the fallback ordering is fragile.
Was this helpful? React with 👍 or 👎 to provide feedback.
…#70 connectors Layout: scripts/ci/termux_smoke/TRACKING.md scripts/ci/termux_smoke/connectors/smoke_connectors.py scripts/ci/termux_smoke/connectors/README.md Offline: file presence, py_compile connector_manager, bash -n health_check.sh. Optional: list connectors if PyYAML present (no network). Wired into termux_smoke.py --with-optional and as a lightweight required presence check.
Connectors → termux_smoke tracking (done)Layout: Wired into
Previous check runs on this PR: repo-gate ✅ termux-smoke ✅ Waiting for the new commit checks; if still green → MERGE #75. Signed-off-by: Grok (ADE) |
| def check_connectors_suite(report: SmokeReport) -> None: | ||
| """Run scripts/ci/termux_smoke/connectors offline suite (#70 tracking).""" | ||
| entry = REPO_ROOT / "scripts/ci/termux_smoke/connectors/smoke_connectors.py" | ||
| connectors_dir = REPO_ROOT / ".github" / "connectors" | ||
| if not entry.is_file(): | ||
| if connectors_dir.is_dir(): | ||
| report.add( | ||
| CheckResult( | ||
| "connectors-suite", | ||
| "FAIL", | ||
| "connectors present but scripts/ci/termux_smoke/connectors/smoke_connectors.py missing", | ||
| ) | ||
| ) | ||
| else: | ||
| report.add(CheckResult("connectors-suite", "NOTE", "no connectors tree and no suite entry", required=False)) | ||
| return | ||
| rc, out, err = run_cmd([sys.executable, str(entry)], timeout=45.0) | ||
| detail = (out or err or f"rc={rc}").replace("\n", " | ")[:240] | ||
| if rc != 0: | ||
| report.add(CheckResult("connectors-suite", "FAIL", detail)) | ||
| else: | ||
| report.add(CheckResult("connectors-suite", "PASS", detail or "ok")) |
There was a problem hiding this comment.
🔍 New connectors suite runs in the core (required) smoke path, not --with-optional as documented
check_connectors_suite is invoked from the non---light core path, and its CheckResults default to required=True, so a FAIL fails the Core smoke (required) step in .github/workflows/termux-smoke.yml. The suite's own README says it runs "via umbrella smoke: python3 scripts/ci/termux_smoke.py --with-optional" (scripts/ci/termux_smoke/connectors/README.md:6-7), and TRACKING.md calls it "core soft-required" (scripts/ci/termux_smoke/TRACKING.md:8). The three descriptions disagree. I verified the suite currently passes on this checkout, but any branch that removes/renames a file in .github/connectors/ (e.g. the planned #74 exchanges extraction, which would drop exchanges.yaml from REQUIRED_FILES at scripts/ci/termux_smoke/connectors/smoke_connectors.py:21-28) will hard-fail the required gate.
Was this helpful? React with 👍 or 👎 to provide feedback.
| if: | | ||
| ( | ||
| github.event_name == 'pull_request' && | ||
| github.event.pull_request.head.repo.fork == false && | ||
| github.event.pull_request.draft == false | ||
| ) || ( | ||
| github.event_name == 'issues' && | ||
| contains(fromJSON('["opened", "reopened"]'), github.event.action) | ||
| ) || ( | ||
| github.event.sender.type == 'User' && | ||
| startsWith(github.event.comment.body || github.event.review.body || '', '@gemini-cli') && | ||
| contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association || github.event.review.author_association || github.event.issue.author_association) | ||
| ) |
There was a problem hiding this comment.
🔍 Dispatch gate skips the author-association check for pull_request events but the third clause can be evaluated for reviews
For pull_request_review.submitted the third clause reads github.event.comment.author_association || github.event.review.author_association || github.event.issue.author_association; review.author_association exists so this works, but for pull_request_review_comment.created the payload's comment.author_association is present too. The clause is also evaluated for pull_request/issues events where all three are null — contains(..., '') is false, so it correctly relies on the earlier clauses. No functional problem found, but note that issues.opened unconditionally triggers a triage run with no @gemini-cli opt-in and no author-association check, which means any user opening an issue consumes Gemini quota.
Was this helpful? React with 👍 or 👎 to provide feedback.
Path is scripts/ci/termux_smoke/connectors/smoke_connectors.py → parents[4] is repo root (was parents[3] → scripts/). Fixes FAIL looking for scripts/.github/connectors. Signed-off-by: Grok (ADE)
|
ADE fix pushed (
That was the only required failure on #70 connectors tracking is live on this branch:
Workflow stack on this PR (ready once smoke is green):
After this run goes green → merge #75 → master-staging, then promote same workflow files to Supersedes bare |
…ation) Completes Jules side of the consolidated agent stack on master-staging. Signed-off-by: Grok (ADE)
|
@jules Auto-resolve (GHA agent-review-auto-jules) — do not wait for a human ping. Feedback excerpt(see review threads) Instructions
|
There was a problem hiding this comment.
🔍 PR does not cite an ITEMS.md id as required by AGENTS.md
AGENTS.md requires Implements: <ITEM-ID> on PRs/commits and forbids work outside docs/proposals/active/<id>/ITEMS.md without adding a row first. The PR body cites Implements: workflow consolidation for operational Gemini stack, which is prose rather than an item id, and no ITEMS.md row is added in this diff. Worth confirming an item row exists (or adding one) before merge.
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
@coderabbitai do this and commit.
Make sure all issues are fixed and committed in this #75 PR high importance merge.
Retarget to master from master-staging
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '== Repository instructions =='
fd -H -t f '^AGENTS\.md$|^ITEMS\.md$' . | sort
if [ -f AGENTS.md ]; then
sed -n '1,260p' AGENTS.md
fi
echo '== Active proposal item rows that mention Gemini, workflow, dispatch, quota, or wiki =='
fd -H -t f '^ITEMS\.md$' docs/proposals/active 2>/dev/null \
| sort \
| while IFS= read -r file; do
echo "--- $file"
rg -n -i -C 2 'gemini|workflow|dispatch|quota|wiki' "$file" || true
done
echo '== Gemini workflow inventory =='
fd -H -t f '^gemini-.*\.ya?ml$|^agent-load-balancer\.ya?ml$' .github/workflows 2>/dev/null | sort
echo '== Pull request `#75` metadata =='
gh pr view 75 --repo timerloggedout-spec/termux-monorepo \
--json number,title,body,baseRefName,headRefName,state,urlLength of output: 7626
🏁 Script executed:
#!/bin/bash
set -euo pipefail
for file in \
.github/workflows/gemini-dispatch.yml \
.github/workflows/gemini-triage.yml \
.github/workflows/gemini-review.yml \
.github/workflows/gemini-invoke.yml \
.github/workflows/agent-load-balancer.yml
do
if [ -f "$file" ]; then
echo "== $file =="
nl -ba "$file" | sed -n '1,260p'
fi
done
echo '== Reusable-workflow entry points and invocations =='
rg -n -C 3 \
'workflow_call|gemini-(dispatch|triage|review|invoke)\.yml|GEMINI_API_KEY|quota' \
.github/workflows 2>/dev/null || trueLength of output: 939
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '== Active proposal registry =='
sed -n '1,260p' docs/proposals/registry.yaml
echo
echo '== Proposal process and PR body process =='
sed -n '1,260p' docs/proposals/PROCESS.md
sed -n '1,260p' docs/PR-SUMMARY-PROCESS.md
echo
echo '== Complete active item lists =='
fd -H -t f '^ITEMS\.md$' docs/proposals/active | sort | while IFS= read -r file; do
echo "--- $file"
sed -n '1,260p' "$file"
done
echo
echo '== Gemini and related workflows =='
for file in \
.github/workflows/gemini-dispatch.yml \
.github/workflows/gemini-triage.yml \
.github/workflows/gemini-review.yml \
.github/workflows/gemini-invoke.yml \
.github/workflows/agent-load-balancer.yml \
.github/actions/gemini-quota-gate/action.yml
do
if [ -f "$file" ]; then
echo "--- $file"
sed -n '1,300p' "$file"
else
echo "--- MISSING: $file"
fi
done
echo
echo '== Gemini workflow references =='
rg -n -C 3 \
'workflow_call|gemini-(dispatch|triage|review|invoke)\.yml|GEMINI_API_KEY|gemini-quota-gate|quota' \
.github/workflows .github/actions 2>/dev/null || trueLength of output: 59878
@timerloggedout-spec, I found two required fixes and one blocked request.
-
Add a new P1 work item in
docs/proposals/active/chatgpt-critical-eval/ITEMS.md, for exampleCE-21, for the Gemini workflow stack. Set its status todoingand cite PR#75as evidence. -
Replace the invalid PR citation with
Implements: CE-21. A permitted summary editor must update the PR body.docs/PR-SUMMARY-PROCESS.mdrestricts CodeRabbit to comments, so I cannot rewrite the PR body. -
Fix
.github/actions/gemini-quota-gate/action.yml. The current daily cache key is immutable. After the first save, later jobs restore the same old counter and cannot persist their increment. The daily quota limit is therefore not reliably enforced. Use a mutable, serialized state mechanism, or redesign the quota gate so it does not rely on updating an existing GitHub Actions cache entry. -
Remove the load-balancer statements from
.github/workflows/gemini-dispatch.yml, or add and invoke.github/workflows/agent-load-balancer.yml. The workflow is missing from this branch and the dispatch workflow does not call it.
I did not retarget #75 to master. AGENTS.md and docs/proposals/PROCESS.md require integration PRs to target master-staging. They specify promotion to master only after master-staging is healthy. Retargeting now would violate the repository policy. EDIT by Human User: ((This is an Exception))
You are interacting with an AI system.
There was a problem hiding this comment.
@coderabbitai fix 1, 2, 3, and 4. The load balancer must be integrated; use it from the other branch to here immediately.
You create commits and PR's all the time; it's what you do!
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '== Repository instructions and proposal item lists =='
fd -H -t f '^AGENTS\.md$|^ITEMS\.md$|^PROCESS\.md$|^PR-SUMMARY-PROCESS\.md$' . | sort
for file in AGENTS.md docs/proposals/PROCESS.md docs/PR-SUMMARY-PROCESS.md; do
if [ -f "$file" ]; then
echo "--- $file"
sed -n '1,260p' "$file"
fi
done
echo '== Active proposal item lists =='
fd -H -t f '^ITEMS\.md$' docs/proposals/active 2>/dev/null | sort | while IFS= read -r file; do
echo "--- $file"
sed -n '1,260p' "$file"
done
echo '== Current Gemini workflow/action structure =='
fd -H -t f -e yml -e yaml .github/workflows .github/actions 2>/dev/null \
| sort \
| grep -E 'gemini|agent-load-balancer' \
| while IFS= read -r file; do
echo "--- $file"
ast-grep outline "$file" --items all || true
done
echo '== Relevant current file contents =='
for file in \
.github/workflows/gemini-dispatch.yml \
.github/workflows/gemini-triage.yml \
.github/workflows/gemini-review.yml \
.github/workflows/gemini-invoke.yml \
.github/actions/gemini-quota-gate/action.yml
do
if [ -f "$file" ]; then
echo "--- $file"
nl -ba "$file" | sed -n '1,360p'
fi
done
echo '== References and quota-gate call sites =='
rg -n -C 4 'agent-load-balancer|gemini-quota-gate|GEMINI_API_KEY|workflow_call|quota' \
.github/workflows .github/actions 2>/dev/null || true
echo '== Pull request and branch inventory =='
gh pr view 75 --repo timerloggedout-spec/termux-monorepo \
--json number,title,body,baseRefName,headRefName,state,url
gh api "repos/timerloggedout-spec/termux-monorepo/branches?per_page=100" \
--paginate --jq '.[].name' | sort
git branch -a --no-color | sed -n '1,160p'
echo '== Locate agent-load-balancer.yml in accessible refs =='
for ref in $(git for-each-ref --format='%(refname:short)' refs/remotes refs/heads | sort -u); do
if git cat-file -e "${ref}:.github/workflows/agent-load-balancer.yml" 2>/dev/null; then
echo "--- REF: $ref"
git show "${ref}:.github/workflows/agent-load-balancer.yml"
fi
doneLength of output: 20000
🏁 Script executed:
#!/bin/bash
set -u
echo '== Pull request `#75` =='
gh pr view 75 --repo timerloggedout-spec/termux-monorepo \
--json number,title,body,baseRefName,headRefName,state,url \
|| true
echo '== Relevant file inventory =='
fd -H -t f -e yml -e yaml .github 2>/dev/null \
| grep -Ei '(gemini|agent-load-balancer)' \
| sort \
|| true
echo '== Dispatch, reusable workflows, and quota action =='
for file in \
.github/workflows/gemini-dispatch.yml \
.github/workflows/gemini-triage.yml \
.github/workflows/gemini-review.yml \
.github/workflows/gemini-invoke.yml \
.github/workflows/agent-load-balancer.yml \
.github/actions/gemini-quota-gate/action.yml
do
if [ -f "$file" ]; then
echo "--- $file"
nl -ba "$file" | sed -n '1,420p'
else
echo "--- MISSING: $file"
fi
done
echo '== All Gemini quota and load-balancer references =='
rg -n -C 5 'agent-load-balancer|gemini-quota-gate|GEMINI_API_KEY|workflow_call|quota' \
.github 2>/dev/null \
|| true
echo '== Remote branches with candidate names =='
gh api "repos/timerloggedout-spec/termux-monorepo/branches?per_page=100" \
--paginate --jq '.[].name' 2>/dev/null \
| grep -Ei 'agent|balanc|gemini|load' \
| sort \
|| true
echo '== Pull requests with candidate names =='
gh pr list --repo timerloggedout-spec/termux-monorepo --state all --limit 100 \
--json number,title,headRefName,baseRefName,url \
--jq '.[] | select((.title + " " + .headRefName) | test("agent|balanc|gemini|load"; "i"))' \
|| true
echo '== Accessible refs containing agent-load-balancer.yml =='
git for-each-ref --format='%(refname:short)' refs/remotes refs/heads 2>/dev/null \
| sort -u \
| while IFS= read -r ref; do
if git cat-file -e "${ref}:.github/workflows/agent-load-balancer.yml" 2>/dev/null; then
echo "--- $ref"
git show "${ref}:.github/workflows/agent-load-balancer.yml"
fi
doneLength of output: 31676
🏁 Script executed:
#!/bin/bash
set -euo pipefail
repo="timerloggedout-spec/termux-monorepo"
source_ref="tembo/agent-quota-loadbalancer"
current_ref="feature/workflows-consolidation"
raw_file() {
local ref="$1"
local path="$2"
echo "--- ${ref}:${path}"
gh api \
-H 'Accept: application/vnd.github.raw+json' \
"repos/${repo}/contents/${path}?ref=${ref}" \
|| true
echo
}
echo '== Source workflow implementations from PR `#72` branch =='
for path in \
.github/workflows/agent-load-balancer.yml \
.github/workflows/gemini-dispatch.yml \
.github/actions/gemini-quota-gate/action.yml \
.github/workflows/gemini-triage.yml \
.github/workflows/gemini-review.yml \
.github/workflows/gemini-invoke.yml
do
raw_file "$source_ref" "$path"
done
echo '== Current PR `#75` branch: complete dispatch and quota action =='
for path in \
.github/workflows/gemini-dispatch.yml \
.github/actions/gemini-quota-gate/action.yml
do
raw_file "$current_ref" "$path"
done
echo '== Source-branch workflow references to the load balancer =='
gh api \
"repos/${repo}/git/trees/${source_ref}?recursive=1" \
--jq '.tree[] | select(.path | test("^\\.github/(workflows|actions)/.*\\.(yml|yaml)$")) | .path' \
| while IFS= read -r path; do
content=$(gh api -H 'Accept: application/vnd.github.raw+json' \
"repos/${repo}/contents/${path}?ref=${source_ref}" 2>/dev/null || true)
if printf '%s\n' "$content" | grep -qi 'agent-load-balancer'; then
echo "--- ${source_ref}:${path}"
printf '%s\n' "$content" | grep -in -C 5 'agent-load-balancer'
fi
doneLength of output: 51045
@timerloggedout-spec, I validated the required changes. I cannot create commits or pull requests. The repository policy also limits CodeRabbit to PR comments. An authorized executor must apply this plan and commit it to feature/workflows-consolidation.
Task: Correct Gemini workflow tracking, quota accounting, and load-balancer routing in #75
- Keep the PR base as
master-staging. It already has the required base. - Add
CE-21as the P1 tracking item. - Replace the prose
Implements:value withImplements: CE-21. - Replace immutable cache-based quota state with mutable, serialized state.
- Add the load-balancer workflow from
tembo/agent-quota-loadbalancer, but correct its incompatible behavior before integration. - Route all Gemini commands through the load balancer.
The agent-load-balancer.yml from #72 must not be copied unchanged. Its quota probe consumes quota, it uses the obsolete 18 limit, and its Gemini route always invokes gemini-review.yml. That behavior would review an issue or on-demand request instead of triaging or invoking it.
🐇⚙️
- 📌 Create a pull request with these changes
You are interacting with an AI system.
| - name: Invoke Jules API (optional) | ||
| if: ${{ secrets.JULES_API_KEY != '' }} | ||
| continue-on-error: true | ||
| uses: google-labs-code/jules-invoke@v1 |
There was a problem hiding this comment.
🔴 Jules issue automation fails to start because the workflow file is rejected
Three steps decide whether to run by reading a stored secret directly inside a step condition (if: ${{ secrets.JULES_API_KEY != '' }} at .github/workflows/agent-jules-on-issues.yml:102), which the workflow engine does not allow, so the whole file is rejected and neither Jules job ever runs.
Impact: Labeling an issue jules or mentioning @jules produces an immediately failing run with no acknowledgement, no fallback ping, and no Jules task.
Why `secrets` is not usable in an `if` expression
GitHub's context-availability rules do not include the secrets context for jobs.<job_id>.steps.<step_id>.if (only github, needs, strategy, matrix, job, runner, env, vars, steps, inputs). Using it yields the parse error Unrecognized named-value: 'secrets', which invalidates the whole workflow file, not just the step.
Affected lines: .github/workflows/agent-jules-on-issues.yml:102, .github/workflows/agent-jules-on-issues.yml:138, .github/workflows/agent-jules-on-issues.yml:232.
The usual workaround is to hoist the secret into a job-level env (secrets ARE allowed in env: / with:) and test env.HAS_JULES_KEY != '' in the if, exactly as the sibling workflows already do with has-backup-key: ${{ secrets.GEMINI_API_KEY_BACKUP != '' }} inside with: (.github/workflows/gemini-invoke.yml:38).
Prompt for agents
The three step-level conditions in .github/workflows/agent-jules-on-issues.yml (lines 102, 138, 232) reference the `secrets` context inside `if:`. GitHub Actions does not expose `secrets` to `if` expressions, so the workflow file fails to parse with 'Unrecognized named-value: secrets' and neither job runs at all. Fix by exposing the presence of the key through a context that IS allowed in `if`, e.g. define a job-level `env: HAS_JULES_KEY: ${{ secrets.JULES_API_KEY }}` (or a boolean-ish string) and change the conditions to test `env.HAS_JULES_KEY != ''` / `== ''`. Apply the same fix to both jobs.
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
@coderabbitai high value fix immediately user demand.
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
workflow=".github/workflows/agent-jules-on-issues.yml"
printf '%s\n' '--- workflow structure ---'
ast-grep outline "$workflow" --items all || true
printf '%s\n' '--- JULES_API_KEY, environment, and conditional references ---'
rg -n -C 4 'JULES_API_KEY|^\s*env:|^\s*if:' "$workflow"Length of output: 3340
🏁 Script executed:
#!/bin/bash
set -euo pipefail
workflow=".github/workflows/agent-jules-on-issues.yml"
printf '%s\n' '--- remaining step-level secret conditions ---'
rg -n -U '^\s{6,}- name:.*\n\s+if:\s*\$\{\{\s*secrets\.' "$workflow" && exit 1 || true
printf '%s\n' '--- Jules key condition and environment references ---'
rg -n -C 2 'JULES_API_KEY|^\s+if:' "$workflow"Length of output: 1031
@timerloggedout-spec, verification failed because the fix is not present on the current branch. The workflow still contains all three invalid secrets.JULES_API_KEY step conditions.
- Apply the planned workflow change before validation.
- Do not mark this finding as resolved until Lines 102, 138, and 232 use
env.JULES_API_KEY.
🐇
- 📌 Commit the changes to this branch
You are interacting with an AI system.
| on: | ||
| issues: | ||
| types: [labeled, opened] | ||
| issue_comment: | ||
| types: [created] | ||
|
|
||
| concurrency: | ||
| group: jules-issue-${{ github.event.issue.number || github.run_id }} | ||
| cancel-in-progress: false |
There was a problem hiding this comment.
📝 Info: Workflow subscribes to issues.opened but no job handles it
on.issues.types includes opened (.github/workflows/agent-jules-on-issues.yml:17) yet both jobs gate on github.event.action == 'labeled' or on issue_comment. Every newly opened issue therefore starts a run in which all jobs are skipped — harmless but noisy in the Actions tab. Either drop opened from the trigger or extend the jules-on-label condition to cover issues opened with the label already applied (a common case when issues are created from templates).
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
@coderabbitai labels are extra.
Fix this so the trigger works.
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
workflow=".github/workflows/agent-jules-on-issues.yml"
printf '%s\n' '--- workflow outline ---'
ast-grep outline "$workflow" --items all || true
printf '%s\n' '--- event guards and payload field references ---'
rg -n -C 4 \
'github\.event\.(action|issue|comment|label)|if:|issues:|issue_comment:' \
"$workflow"
printf '%s\n' '--- full workflow with line numbers ---'
cat -n "$workflow"Length of output: 16921
- Make new issues invoke Jules without a
juleslabel. - Keep the existing
@julesissue-comment invocation path. - Restrict automatic invocation to trusted issue authors.
@timerloggedout-spec, confirmed. Line 29 makes the current issue job label-dependent. The update will invoke Jules when a trusted user opens an issue. It will not require a label.
- 📌 Create a pull request with these changes
You are interacting with an AI system.
|
@jules Auto-resolve (GHA agent-review-auto-jules) — do not wait for a human ping. Feedback excerpt(see review threads) Instructions
|
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
| - name: Restore quota counter | ||
| id: restore | ||
| uses: actions/cache/restore@v4 | ||
| with: | ||
| path: /tmp/gemini-quota | ||
| key: gemini-quota-${{ steps.date.outputs.key }} | ||
| restore-keys: gemini-quota-${{ steps.date.outputs.key }} | ||
| enableCrossOsArchive: true |
There was a problem hiding this comment.
📝 Info: Quota gate never restores the backup counter path correctly after a skip-only run
When the primary counter is exhausted and no backup key is configured, the step sets skip=true and the Save quota counter step is skipped (.github/actions/gemini-quota-gate/action.yml:120). That is fine for the counter itself, but note the backup counter is only ever written, never reset, and both counters live in the same cache entry keyed by date; a day rollover creates a fresh (empty) cache so both reset together — intended behaviour, but only because restore-keys is an exact-date prefix. If someone later loosens restore-keys to gemini-quota- the gate would silently import yesterday's counts and refuse to run all day.
Was this helpful? React with 👍 or 👎 to provide feedback.
| jules-on-label: | ||
| if: | | ||
| github.event_name == 'issues' && | ||
| github.event.action == 'labeled' && | ||
| ( | ||
| github.event.label.name == 'jules' || | ||
| github.event.label.name == 'Jules' || | ||
| github.event.label.name == 'JULES' | ||
| ) |
There was a problem hiding this comment.
🔍 Dispatch gate does not restrict who can label/trigger, despite the security comment
The dispatch condition allows any pull_request opened/synchronize from a non-fork branch, and comment paths are limited to OWNER/MEMBER/COLLABORATOR. However agent-jules-on-issues.yml's label-triggered job has no author-association check at all, so anyone who can add the jules label (triage-permission users) can start API-consuming work, which conflicts with the header comment "Issue triggers are restricted — untrusted openers cannot burn quota" (.github/workflows/agent-jules-on-issues.yml:13). Worth aligning the comment with the actual gating or adding an association check to the label job.
Was this helpful? React with 👍 or 👎 to provide feedback.
LOAD BALANCE ≠ or = async sequential and parallelization Optimizations...?Optimized Runner ≠ Token Rotations.@coderabbitai From, likely stale, @Vibe-Mistral chat: Did @jules loop in a Linear operation? |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
repo="timerloggedout-spec/termux-monorepo"
echo "== PR `#75` state =="
gh pr view 75 --repo "$repo" \
--json url,baseRefName,headRefName,headRefOid,statusCheckRollup \
--jq '{url,baseRefName,headRefName,headRefOid,checks:[.statusCheckRollup[]|{name:(.name // .context),status,conclusion}]}'
echo
echo "== Cited commits and changed paths =="
for sha in bf883d2 1960532 dbeed4b 4d83529 6b69d13 7d91787; do
echo "--- $sha ---"
if gh api "repos/$repo/commits/$sha" --jq '{sha:.sha,message:.commit.message,html_url,files:[.files[].filename]}' 2>/dev/null; then
:
else
echo "NOT FOUND in $repo"
fi
done
echo
echo "== Current Jules and agent workflow inventory =="
fd -H -t f -e yml -e yaml .github/workflows \
| sort \
| while IFS= read -r file; do
case "$file" in
*jules*|*agent*|*gemini*|*linear*)
echo "--- $file ---"
sed -n '1,360p' "$file"
;;
esac
done
echo
echo "== Current Linear references with context =="
rg -n -i -C 4 \
'linear(\.app|[-_ ]?(api|issue|ticket|project)|_API_KEY|_TOKEN)|LINEAR' \
.github AGENTS.md README.md docs scripts 2>/dev/null || true
echo
echo "== Git history affecting Jules/Linear workflow paths =="
git log --all --oneline -- \
.github/workflows \
.github/actions \
| rg -i 'jules|linear|automation|retroactive|gemini' \
| head -n 120 || trueLength of output: 4694 🏁 Script executed: #!/bin/bash
set -euo pipefail
repo="timerloggedout-spec/termux-monorepo"
echo "== Workflow files related to Jules, agents, Gemini, and Linear =="
fd . .github/workflows -t f -e yml -e yaml \
| sort \
| while IFS= read -r file; do
case "${file,,}" in
*jules*|*agent*|*gemini*|*linear*)
echo "--- $file ---"
nl -ba "$file" | sed -n '1,420p'
;;
esac
done
echo
echo "== Linear references in workflow and action definitions =="
rg -n -i -C 5 \
'sync-linear|linear(\.app|[-_ ]?(api|issue|ticket|project)|_API_KEY|_TOKEN)|LINEAR|workflow_run|workflow_dispatch|repository_dispatch' \
.github/workflows .github/actions 2>/dev/null || true
echo
echo "== Recent sync-linear workflow runs =="
gh run list --repo "$repo" --workflow "sync-linear" --limit 30 \
--json databaseId,workflowName,displayTitle,event,headBranch,headSha,status,conclusion,createdAt,url \
--jq '.[] | {databaseId,workflowName,displayTitle,event,headBranch,headSha,status,conclusion,createdAt,url}' \
|| true
echo
echo "== Triggering details and jobs for the latest sync-linear runs =="
for run_id in $(gh run list --repo "$repo" --workflow "sync-linear" --limit 5 --json databaseId --jq '.[].databaseId'); do
echo "--- run $run_id ---"
gh run view "$run_id" --repo "$repo" \
--json event,displayTitle,headBranch,headSha,jobs,url \
--jq '{event,displayTitle,headBranch,headSha,url,jobs:[.jobs[]|{name,status,conclusion,steps:[.steps[]|{name,conclusion}]}]}' \
|| true
done
echo
echo "== Jules workflow references to Linear or workflow dispatch =="
jules_files=$(fd -i '.*jules.*\.ya?ml$' .github/workflows -t f || true)
if [ -n "$jules_files" ]; then
printf '%s\n' "$jules_files" | while IFS= read -r file; do
echo "--- $file ---"
rg -n -i -C 5 \
'linear|workflow_dispatch|repository_dispatch|gh workflow|actions/github-script|jules' \
"$file" || true
done
else
echo "No Jules workflow file found."
fiLength of output: 2446 🏁 Script executed: #!/bin/bash
set -euo pipefail
repo="timerloggedout-spec/termux-monorepo"
echo "== Linear synchronization workflow =="
if [ -f .github/workflows/agent-feedback-linear-sync.yml ]; then
cat .github/workflows/agent-feedback-linear-sync.yml
fi
echo
echo "== Jules workflow files =="
fd -i '.*jules.*\.ya?ml$' .github/workflows -t f \
| sort \
| while IFS= read -r file; do
echo "--- $file ---"
cat "$file"
done
echo
echo "== References that connect Linear synchronization to other workflows =="
rg -n -i -C 6 \
'sync-linear|agent-feedback-linear-sync|linear|workflow_dispatch|repository_dispatch|workflow_run' \
.github/workflows .github/actions 2>/dev/null || true
echo
echo "== Recent sync-linear workflow runs =="
gh run list --repo "$repo" --workflow "sync-linear" --limit 10 \
--json databaseId,displayTitle,event,headBranch,headSha,status,conclusion,createdAt,url \
--jq '.[] | {databaseId,displayTitle,event,headBranch,headSha,status,conclusion,createdAt,url}' \
|| true
echo
echo "== Latest sync-linear run job steps =="
for run_id in $(gh run list --repo "$repo" --workflow "sync-linear" --limit 3 --json databaseId --jq '.[].databaseId'); do
echo "--- run $run_id ---"
gh run view "$run_id" --repo "$repo" --json event,displayTitle,headBranch,headSha,jobs,url \
--jq '{event,displayTitle,headBranch,headSha,url,jobs:[.jobs[]|{name,status,conclusion,steps:[.steps[]|{name,conclusion}]}]}' \
|| true
doneLength of output: 33079
The repository does contain a Linear operation:
The apparent connection is indirect:
So, the current behavior is parallel fan-out, not a Jules feedback loop: There are still important defects:
On terminology:
These are separate controls. A concurrency group can serialize Gemini quota updates. It is not a load balancer. API-key rotation is not runner optimization. A valid load balancer must route work to a real fallback executor without consuming quota during a probe. The cited commit IDs ( 🐇🔎 You are interacting with an AI system. |
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
| ) || ( | ||
| github.event_name == 'issues' && | ||
| contains(fromJSON('["opened", "reopened"]'), github.event.action) | ||
| ) || ( |
There was a problem hiding this comment.
🔍 Issue-opened triage bypasses the author-association allowlist
The dispatch condition gates comment-driven commands behind OWNER/MEMBER/COLLABORATOR, but the issues branch (contains(fromJSON('["opened", "reopened"]'), github.event.action)) has no such restriction, so any external user opening an issue triggers a Gemini triage run and consumes a slot of the daily quota. The Jules workflow header claims "Issue triggers are restricted — untrusted openers cannot burn quota"; that claim does not hold for this dispatcher. Consider applying the same author-association filter to the issues branch.
Was this helpful? React with 👍 or 👎 to provide feedback.
| const agentLogins = ['google-labs-jules[bot]', 'devin-ai-integration[bot]', 'coderabbitai[bot]', 'ecc-tools[bot]']; | ||
| const relevant = prs.filter(p => { | ||
| const u = (p.user && p.user.login) || ''; | ||
| const body = (p.body || '') + ' ' + (p.title || ''); | ||
| return agentLogins.some(a => u.includes(a.split('[')[0])) || | ||
| body.includes(`#${issue}`) || | ||
| body.toLowerCase().includes(`issue ${issue}`); | ||
| }).slice(0, 15); |
There was a problem hiding this comment.
📝 Info: Agent-login matching in the label job strips the bot suffix, widening the filter
agentLogins.some(a => u.includes(a.split('[')[0])) reduces 'google-labs-jules[bot]' to 'google-labs-jules' before substring matching, so the filter is intentionally loose — fine. But note the mention job at .github/workflows/agent-jules-on-issues.yml:203-207 already stores the bare logins and does a plain u.includes(a); the two lists are duplicated with different shapes and will drift. Also both filters look only at p.body/p.title for #<issue>, so a PR referencing the issue only in commit messages or via the linked-issue API is not detected.
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
scripts/ci/termux_smoke/connectors/smoke_connectors.py (2)
113-119: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winReject invalid
list_connectors()results.The
elsebranch printstype(c).__name__and exits with status zero.check_list_optional()then recordsPASSfor a non-dictionary result. It also accepts dictionaries with non-list values.Validate the
Dict[str, List[str]]contract from.github/connectors/connector_manager.pyLines [136-154] before printing the result. Raise an error for invalid keys or values so the report does not claimPASS.🤖 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 `@scripts/ci/termux_smoke/connectors/smoke_connectors.py` around lines 113 - 119, Update the ConnectorManager smoke-test code in check_list_optional() to require list_connectors() to return a dictionary whose keys are strings and whose values are lists of strings. Raise an error for any invalid result instead of printing its type, while preserving sorted-key output for valid dictionaries so invalid cases produce a nonzero exit and cannot be reported as PASS.
129-134: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winLimit dependency skips to known optional imports.
check_list_optionalcurrently treats everyModuleNotFoundErroras optional and reports"PyYAML/requests not installed". Ifconnector_managerimports another internal or missing dependency, this turns a required startup failure into an optional note while the syntax compile step still passes. Useexc.namefrom the caught import error and skip only optional dependencies such asyamlandrequests; add all other errors toReport.failedso the suite does not pass.🤖 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 `@scripts/ci/termux_smoke/connectors/smoke_connectors.py` around lines 129 - 134, Update check_list_optional to catch the import failure and inspect ModuleNotFoundError.name, skipping only known optional dependencies such as yaml and requests. For any other missing dependency or startup error, add the failure to Report.failed rather than recording an optional NOTE, while preserving the existing successful connector-list behavior.
🤖 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 `@scripts/ci/termux_smoke/connectors/smoke_connectors.py`:
- Around line 78-84: Update the subprocess.run calls in the smoke-check flow to
use check=False and catch subprocess.TimeoutExpired and OSError before report
generation. Record required FAIL results for connector-manager-compile and
health-check-syntax, and an optional NOTE for connectors-list, while preserving
final print/JSON output and returncode inspection for completed processes.
---
Outside diff comments:
In `@scripts/ci/termux_smoke/connectors/smoke_connectors.py`:
- Around line 113-119: Update the ConnectorManager smoke-test code in
check_list_optional() to require list_connectors() to return a dictionary whose
keys are strings and whose values are lists of strings. Raise an error for any
invalid result instead of printing its type, while preserving sorted-key output
for valid dictionaries so invalid cases produce a nonzero exit and cannot be
reported as PASS.
- Around line 129-134: Update check_list_optional to catch the import failure
and inspect ModuleNotFoundError.name, skipping only known optional dependencies
such as yaml and requests. For any other missing dependency or startup error,
add the failure to Report.failed rather than recording an optional NOTE, while
preserving the existing successful connector-list behavior.
🪄 Autofix
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: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 45ecbcb8-9dcf-4226-b66a-62ec59ed5ca5
📒 Files selected for processing (3)
.github/workflows/agent-jules-on-issues.ymlscripts/ci/termux_smoke.pyscripts/ci/termux_smoke/connectors/smoke_connectors.py
| proc = subprocess.run( | ||
| [sys.executable, "-B", "-c", code, str(path), cfile], | ||
| cwd=REPO_ROOT, | ||
| capture_output=True, | ||
| text=True, | ||
| timeout=30, | ||
| ) |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n -C 5 'subprocess\.run|TimeoutExpired|FileNotFoundError|check=' \
scripts/ci/termux_smoke/connectors/smoke_connectors.pyRepository: timerloggedout-spec/termux-monorepo
Length of output: 1664
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== file size =="
wc -l scripts/ci/termux_smoke/connectors/smoke_connectors.py
echo "== full smoke connectors outline and relevant sections =="
sed -n '1,180p' scripts/ci/termux_smoke/connectors/smoke_connectors.py | cat -n
echo "== imports at top =="
sed -n '1,40p' scripts/ci/termux_smoke/connectors/smoke_connectors.py | cat -n
echo "== exception handling in file =="
rg -n 'except|TimeoutExpired|FileNotFoundError|OSError|sys\.exit|finally|Reporter|Result|report\.' scripts/ci/termux_smoke/connectors/smoke_connectors.pyRepository: timerloggedout-spec/termux-monorepo
Length of output: 10246
Handle subprocess failures before emitting the report.
subprocess.run(..., timeout=...) raises TimeoutExpired, and missing executor paths raise FileNotFoundError; these exceptions can skip the final print/JSON output. Catch TimeoutExpired and OSError at lines 78-84, 100, and 121-126, record required FAIL results for connector-manager-compile and health-check-syntax, and record an optional NOTE for connectors-list. Set check=False for each run before inspection of returncode.
🧰 Tools
🪛 Pylint (4.0.6)
[warning] 78-84: 'subprocess.run' used without explicitly defining the value for 'check'.
(W1510)
🪛 Ruff (0.16.1)
[error] 78-78: subprocess call: check for execution of untrusted input
(S603)
[warning] 78-78: subprocess.run without explicit check argument
Add explicit check=False
(PLW1510)
🤖 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 `@scripts/ci/termux_smoke/connectors/smoke_connectors.py` around lines 78 - 84,
Update the subprocess.run calls in the smoke-check flow to use check=False and
catch subprocess.TimeoutExpired and OSError before report generation. Record
required FAIL results for connector-manager-compile and health-check-syntax, and
an optional NOTE for connectors-list, while preserving final print/JSON output
and returncode inspection for completed processes.
Source: Linters/SAST tools
…omment triggers - Dispatch outputs issue_number and passes pr_number to reusable workflows - Reusable workflows accept pr_number input and prefer it over github.event.* so issue_comment / review_comment paths still reach quota-gate + Gemini CLI - Keeps SHA-pinned run-gemini-cli and existing concurrency/quota behavior Prepares #75 for merge to master-staging.
Ready for merge →
|
| Piece | Status |
|---|---|
gemini-quota-gate (RPD 900 Pacific, multi-key, graceful skip) |
✅ |
gemini-dispatch central router + pr_number output |
✅ |
gemini-review / triage / invoke (SHA-pinned CLI, session bookmark) |
✅ |
agent-jules-on-issues |
✅ |
publish-wiki |
✅ |
termux-smoke + connectors suite (parents[4], tempdir compile) |
✅ green |
| repo-gate / hygiene | ✅ green |
| Aikido | non-blocking (third-party pin noise) |
After you merge to master-staging
- Promote the same workflow files to
master(event triggers need the default branch). - Close/supersede fix(ci): add continue-on-error to Gemini CLI workflows #71; narrow feat: agent quota throttling, session continuation & load balancing #72.
- Continue exchanges extraction on [CLOSED - spliced out] feat(exchanges): dedicated financial exchange connectors (Yobit/KuCoin/Binance) #74.
You can merge #75 when the new-commit checks settle (repo-gate + termux-smoke expected green). Aikido can stay red.
| prompt: | | ||
| You are the free-tier agentic PR reviewer for termux-monorepo. | ||
| Read GEMINI.md and AGENTS.md. | ||
|
|
||
| Review this pull request for: | ||
| - Correctness and regressions | ||
| - Security (credentials, session stores, chmod 0o600/0o700) | ||
| - Alignment with AGENTS.md (master-staging, gates, no Class 3/4 artifacts) | ||
| - Minimal-diff preference | ||
| - Overlap with other open agent PRs: ${{ inputs.prior_prs }} | ||
|
|
||
| ${{ steps.session.outputs.changed_files != '' && format('## Changed files since last review\nFocus here:\n{0}', steps.session.outputs.changed_files) || '## Full review (first pass)' }} | ||
|
|
||
| Post a concise review comment. Prefer a comment over formal approve/request-changes. | ||
| End your comment with: <!-- gemini-review-sha: ${{ steps.session.outputs.reviewed_sha }} --> | ||
|
|
||
| Additional context: ${{ inputs.additional_context }} |
There was a problem hiding this comment.
Prompt Injection in GitHub Workflows Action - critical severity
A GitHub Actions workflow contains a AI inference prompt, referencing potentially untrusted GitHub context fields. This may allow malicious input to be injected into the prompt, which makes the output of the prompt highly insecure. If the output is used to execute a command, they could potentially exfiltrate data from the pipeline (e.g. highly privileged secrets).
Show fix
Remediation: Avoid directly passing untrusted GitHub context values into AI inference prompts, especially when those values originate from user-controlled fields such as body, title, head_ref, email, or commit messages. Treat all GitHub context fields as potentially malicious input. Restrict LLM tool and write access.
Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info
|
@jules Auto-resolve (GHA agent-review-auto-jules) — do not wait for a human ping. Feedback excerpt(see review threads) Instructions
|
| github_pr_number: ${{ inputs.pr_number || github.event.pull_request.number }} | ||
| github_issue_number: ${{ inputs.pr_number || github.event.issue.number }} |
There was a problem hiding this comment.
🔍 Invoke workflow passes the same number as both PR and issue number
github_pr_number and github_issue_number are both fed from inputs.pr_number (.github/workflows/gemini-invoke.yml:53-54), which dispatch sets from either pull_request.number or issue.number (.github/workflows/gemini-dispatch.yml:83-87). For an issue-comment invoke this passes an issue number as github_pr_number, and for a PR-comment invoke it passes a PR number as github_issue_number. Worth verifying how run-gemini-cli reacts when both are set to a value that is not of the expected kind — it may attempt PR-specific API calls against an issue.
Was this helpful? React with 👍 or 👎 to provide feedback.
| shell: bash | ||
|
|
||
| - name: Save quota counter | ||
| if: always() && steps.check.outputs.skip != 'true' |
There was a problem hiding this comment.
📝 Info: Quota counter is saved even when the gate step itself failed
The save step uses if: always() && steps.check.outputs.skip != 'true'. If the check script aborts (e.g. set -eu trips before any output is written), skip is empty, so the condition holds and the cache is saved — possibly persisting a partially written or unchanged counter directory under a fresh key. Gating on steps.check.outputs.skip == 'false' would be tighter.
Was this helpful? React with 👍 or 👎 to provide feedback.
| on: | ||
| pull_request: | ||
| types: [opened, synchronize, ready_for_review] | ||
| issues: | ||
| types: [opened, reopened] | ||
| issue_comment: | ||
| types: [created] | ||
| pull_request_review_comment: | ||
| types: [created] | ||
| pull_request_review: | ||
| types: [submitted] |
There was a problem hiding this comment.
📝 Info: Dispatch acknowledges every PR push, consuming quota per synchronize
The dispatch job triggers on pull_request.synchronize and routes to the review workflow, so every push to an open non-draft PR consumes one unit of the daily Gemini budget and posts/updates review output. Combined with the session-continuation check keyed on head SHA this is intended, but on busy branches it can burn quota quickly; consider paths-ignore or debouncing if RPD pressure appears.
Was this helpful? React with 👍 or 👎 to provide feedback.
| prompt: | | ||
| You are Jules working on termux-monorepo. Read AGENTS.md and GEMINI.md if present. | ||
|
|
||
| ## Issue #${{ github.event.issue.number }}: ${{ github.event.issue.title }} | ||
|
|
||
| ${{ github.event.issue.body }} | ||
|
|
||
| ## Open agent / related PRs (DO NOT overlap files) | ||
| ${{ steps.coord.outputs.prior_prs }} |
There was a problem hiding this comment.
🟨 Untrusted issue title/body interpolated directly into agent action inputs
.github/workflows/agent-jules-on-issues.yml:111-113 (and :239-244) interpolate github.event.issue.title, github.event.issue.body, and github.event.comment.body directly into the prompt: input of the third-party google-labs-code/jules-invoke@v1 action. These values are fully attacker-controlled by anyone who can open an issue; the label-triggered job only requires that a maintainer applies the jules label, so the content itself is never trusted. An issue body containing agent instructions can steer Jules (which then creates branches/PRs with repo write access) into unintended changes — classic prompt/agent injection. The repository's AGENTS.md places hard constraints on agent behavior (base branch, no Class 3/4 artifacts, no invented work) that injected instructions can attempt to override.
Was this helpful? React with 👍 or 👎 to provide feedback.
| ) || ( | ||
| github.event_name == 'issues' && | ||
| contains(fromJSON('["opened", "reopened"]'), github.event.action) | ||
| ) || ( |
There was a problem hiding this comment.
🟨 Any user opening an issue can trigger Gemini runs and consume API quota
.github/workflows/gemini-dispatch.yml:37-40 allows any issues.opened/reopened event to dispatch the triage job with no author-association check, unlike the comment path at :41-44 which restricts to OWNER/MEMBER/COLLABORATOR. Anyone (including drive-by accounts) can therefore cause repeated Gemini API calls with issues: write / pull-requests: write permissions, draining the shared free-tier daily budget tracked by .github/actions/gemini-quota-gate/action.yml and denying the capability to maintainers. The Jules workflow header explicitly claims 'Issue triggers are restricted — untrusted openers cannot burn quota', which this dispatch path does not honor.
Was this helpful? React with 👍 or 👎 to provide feedback.
Workflows-only promote from #75 (master-staging) so event triggers fire on the default branch. Includes pr_number plumbing for comment triggers and RPD 900 quota gate. Signed-off-by: Grok (ADE)
Summary
ADE consolidation branch — cherry-picks the operational GitHub Actions workflow stack onto
master-stagingso gates + agent workflows live together, then can be promoted tomasterfor event triggers.Already on this branch
.github/actions/gemini-quota-gate/action.yml— RPD safety margin 900 (not 18/20), midnight Pacific reset, multi-key rotation, graceful skip commentgemini-dispatch.yml— central router (Agent2Agent comments @gemini-cli)gemini-triage.yml/gemini-invoke.yml— quota-aware reusable workflowspublish-wiki.yml— from masterrepo-gate.yml,termux-smoke.yml, agent-feedback, auto-julesACTION WORKFLOWS SKIP
termux-smoke(different environment function) && SKIPmaster-stagingwhen ready to merge and test; Must be onmaster.Still being pushed (follow-up commits on this branch)
gemini-review.yml(session continuation + quota gate) — required before merge (dispatchreviewjob calls it)agent-load-balancer.ymlagent-jules-on-issues.yml(from master)Why not #72 as-is
#72 is
mergeable_state: dirty(79 files, conflicts with current master-staging). This PR is workflows-only so it can land cleanly.After merge to master-staging
master(event triggers require default branch).Test
on any non-draft PR after promotion to master.
Implements: workflow consolidation for operational Gemini stack
Signed-off-by: Grok (ADE)
Summary by CodeRabbit
Summary by CodeRabbit