Skip to content

Comments

feat(ci): add daily GitHub Action to update claude-agent-sdk#36

Open
jeremyeder wants to merge 5 commits intomainfrom
claude/daily-sdk-update-action-tuNV9
Open

feat(ci): add daily GitHub Action to update claude-agent-sdk#36
jeremyeder wants to merge 5 commits intomainfrom
claude/daily-sdk-update-action-tuNV9

Conversation

@jeremyeder
Copy link
Owner

Adds a scheduled workflow that runs daily at 8 AM UTC to check PyPI
for the latest claude-agent-sdk version and opens a PR if a newer
version is available.

https://claude.ai/code/session_01AF1ro2VAMS7WSb7QayTetZ

Adds a scheduled workflow that runs daily at 8 AM UTC to check PyPI
for the latest claude-agent-sdk version and opens a PR if a newer
version is available.

https://claude.ai/code/session_01AF1ro2VAMS7WSb7QayTetZ
- Replace pip index with PyPI JSON API (curl+jq) — removes setup-python step
- Add version format validation to reject unexpected PyPI responses
- Use sort -V for proper semver comparison — prevents downgrade PRs
- Escape dots in sed regex to avoid wildcard matches
- Merge update and validate steps into one
- Build PR body in a variable instead of inline heredoc
- Add failure case to step summary
- Use POSIX = instead of bash == in test expressions

https://claude.ai/code/session_01AF1ro2VAMS7WSb7QayTetZ
@jeremyeder
Copy link
Owner Author

I did this from my phone using the Claude App.

@github-actions

This comment has been minimized.

- Pin actions/checkout to commit SHA (de0fac2e, v6.0.2) for supply chain security
- Move all ${{ steps.*.outputs.* }} into env: blocks to prevent expression injection
- Add concurrency group to prevent parallel workflow races
- Add timeout-minutes: 15 to the job
- Add --max-time 30 to curl for PyPI requests
- Replace silent 2>/dev/null || true with diagnostic echo on branch delete
- Remove --label "dependencies" flag (label may not exist in repo)

https://claude.ai/code/session_01AF1ro2VAMS7WSb7QayTetZ
@github-actions
Copy link

github-actions bot commented Feb 20, 2026

Claude Code Review

Summary

Adds a scheduled daily workflow that polls PyPI for claude-agent-sdk updates and opens an automated PR when a newer version is available. The implementation has been well-hardened across three commits (SHA-pinned action, expression injection mitigations, concurrency guard, timeout, curl timeout, --label fix). One functional gap remains before this is fully production-safe.

Note: The previous automated review (now marked outdated) identified --label dependencies as Critical - this was correctly resolved in f526522. The review below reflects the current state of the PR.

Issues by Severity

Blocker Issues

None.

Critical Issues

None.

Major Issues

1. uv.lock is not updated alongside pyproject.toml

components/runners/claude-code-runner/uv.lock exists and explicitly pins the dependency. The workflow only stages pyproject.toml (line 137). Every automated PR will leave uv.lock pointing to the old minimum version. CLAUDE.md specifies uv as the preferred package manager, and a committed lockfile implies reproducible installs. While runner-tests.yml currently uses pip install -e . (ignores the lock), tightening CI to uv sync --frozen would cause all future automated PRs to immediately fail their own test plan.

Suggested fix: add a uv lock step before the commit and include uv.lock in git add.

Minor Issues

2. PR body markdown will not render correctly

The multi-line PR_BODY variable is assigned inside an indented shell block (lines 146-161). All subsequent lines carry ~10 leading spaces from the shell indentation. CommonMark treats 4+ leading spaces as a preformatted code block, so headings and bullet points will render as raw text/code rather than formatted markdown in the generated PRs.

3. Stale-PR summary omits version and PR number

When pr_exists=true the step summary (line 183) only says an open PR exists for the branch. Adding the existing PR URL and the version it targets would save an operator the manual lookup.

4. Version extraction regex is slightly permissive

Line 54 uses [0-9][0-9.]* in sed, which can match strings ending in a dot or with consecutive dots. Risk is minimal since pyproject.toml is a controlled file, but mirroring the strict regex already used for LATEST would make both validations consistent.

5. sort -V tie-break behavior is non-obvious

When CURRENT == LATEST, sort -V emits two identical lines and tail -1 returns one; the equality check is true, correctly reporting already-up-to-date. This is correct but a short comment would help future readers understand the equal-version edge case.

Positive Highlights

  • SHA-pinned checkout (actions/checkout@de0fac2e) - correct supply chain mitigation.
  • Expression injection hardening - all steps outputs references are in env: blocks, not interpolated directly into run: scripts.
  • concurrency group with cancel-in-progress: false prevents parallel race conditions.
  • timeout-minutes: 15 prevents zombie jobs.
  • curl --max-time 30 prevents PyPI fetch from hanging indefinitely.
  • Strict version format validation rejects pre-release strings and malformed PyPI responses before they reach sed.
  • Dot-escaping in sed (CURRENT_ESC) avoids wildcard matches on version dots.
  • Post-update verification (grep -q) catches a failed substitution before committing.
  • Duplicate PR guard prevents stacked open PRs when a previous update is still under review.
  • sort -V is the correct POSIX tool for semantic version comparison.
  • Four-state step summary covers all terminal outcomes (up-to-date, PR exists, failed, PR created).

Recommendations

  1. Before merge: Add uv lock regeneration and include uv.lock in the commit (Major Epic: MPP Deployment - Single-Namespace vTeam Implementation #1).
  2. Before merge or immediate follow-up: Fix the PR body indentation so generated PRs render proper markdown (Minor [Phase 1] Add SINGLE_NAMESPACE_MODE support to operator #2).
  3. Optional: Enrich the PR-exists summary with the existing PR URL and version (Minor [Phase 1] Disable project creation endpoint in backend for single-namespace mode #3).

🔍 View AI decision process (logs available for 90 days)

📋 View memory system files loaded (click to expand)

What Amber Loaded for Code Review

Amber automatically loaded these repository standards from the memory system:

  1. CLAUDE.md - Master project instructions, development standards
  2. backend-development.md - Go backend, K8s integration patterns
  3. frontend-development.md - NextJS, Shadcn UI, React Query patterns
  4. security-standards.md - Auth, RBAC, token handling
  5. k8s-client-usage.md - User token vs service account patterns
  6. error-handling.md - Consistent error patterns
  7. react-query-usage.md - Data fetching patterns

Impact: This review used your repository's specific code quality standards, security patterns, and best practices from the memory system (PRs ambient-code#359, ambient-code#360) - not just generic code review guidelines.

- Add uv lock regeneration step after pyproject.toml update to keep
  uv.lock in sync and prevent broken local dev environments
- Include uv.lock in the auto-generated commit
- Document GITHUB_TOKEN CI triggering limitation in auto-generated PR body
  (PRs created by GITHUB_TOKEN don't trigger pull_request workflows)
- Add defensive default (|| 'false') for PR_EXISTS env in Summary step
  when existing_pr step is skipped
- Fix PR body formatting via heredoc to avoid indentation artifacts

https://claude.ai/code/session_01AF1ro2VAMS7WSb7QayTetZ
@github-actions
Copy link

github-actions bot commented Feb 21, 2026

Claude Code Review

Summary

This PR adds a scheduled daily workflow to poll PyPI for claude-agent-sdk updates and open automated PRs when a newer version is found. Across four commits the implementation has been substantially hardened. Two issues flagged in prior automated reviews (uv.lock not updated, PR body markdown indentation) have been resolved in the latest commit (319c62d). The workflow is now close to merge-ready; only minor items remain.

Issues by Severity

🚫 Blocker Issues

None.

🔴 Critical Issues

None.

🟡 Major Issues

None. The previously flagged uv.lock drift issue was fixed in 319c62d — the Regenerate uv.lock step now runs uv lock and the commit includes uv.lock alongside pyproject.toml.

🔵 Minor Issues

1. pip install uv is unpinned

- name: Regenerate uv.lock
  run: |
    pip install uv     # no version pin

An unpinned uv bootstrap means the runner could silently pick up a breaking uv release. Options:

  • Use the official action: astral-sh/setup-uv@v4 (preferred — handles caching and pinning)
  • Or pin explicitly: pip install uv==0.6.1

2. sort -V equal-version tie-break is non-obvious

NEWEST=$(printf '%s\n%s' "$CURRENT" "$LATEST" | sort -V | tail -1)
if [ "$NEWEST" = "$CURRENT" ]; then

When CURRENT == LATEST, sort -V outputs two identical lines and tail -1 picks either; the equality check correctly reports "already up-to-date". This is correct but a one-line comment would help future maintainers understand the edge case without working through the logic.

3. sed version extraction regex is slightly permissive

sed 's/.*>=\([0-9][0-9.]*\).*/\1/'

[0-9][0-9.]* could match malformed strings like 1..2 or 1. (consecutive/trailing dots). The risk is minimal for a controlled file like pyproject.toml, but using the same strict pattern already applied to LATEST ([0-9]+(\.[0-9]+)+) would make both validations consistent.

4. Stale-PR summary branch message could be richer

echo "An open PR for branch \`auto/update-claude-agent-sdk\` already exists." >> "$GITHUB_STEP_SUMMARY"

Adding the existing PR URL (from gh pr list) and the version it targets would save an operator the manual lookup step when triaging the daily summary.

5. No post-lock verification

After uv lock, the workflow does not verify uv.lock was actually modified. A git diff --stat components/runners/claude-code-runner/uv.lock output line (not exit-1 on no change, just informational) would confirm the lock round-tripped correctly.

Positive Highlights

  • SHA-pinned checkout (actions/checkout@de0fac2e) — correct supply chain mitigation.
  • Expression injection hardening — all steps.*.outputs.* references live in env: blocks; none are interpolated directly into run: scripts.
  • Concurrency group with cancel-in-progress: false — prevents parallel races without silently dropping a scheduled run.
  • timeout-minutes: 15 + curl --max-time 30 — prevents zombie jobs and hung PyPI fetches.
  • Strict version format validation before the version reaches sed — guards against pre-release strings and malformed PyPI responses.
  • Dot-escaping in sed (CURRENT_ESC) — avoids wildcard matches on version dots; easy to get wrong, correctly handled here.
  • Post-update grep verification — confirms substitution landed before committing.
  • Duplicate PR guard — prevents stacked open PRs when a previous update is still under review.
  • sort -V — correct POSIX tool for semantic version comparison; prevents accidental downgrade.
  • Four-state step summary (up-to-date / PR exists / failed / PR created) — good operational visibility.
  • PR body documents the GITHUB_TOKEN CI triggering limitation — accurate and useful for maintainers who wonder why CI doesn't run automatically on the generated PRs.
  • uv.lock included in auto-commit (fixed in 319c62d) — keeps the lockfile in sync and prevents drift.
  • Heredoc at column 0 (fixed in 319c62d) — PR body markdown now renders correctly.

Recommendations

  1. (Optional, before merge) Replace pip install uv with astral-sh/setup-uv@v4 for a pinned, cached install.
  2. (Nice-to-have) Add a comment on the sort -V equality branch explaining the tie-break behavior.
  3. (Nice-to-have) Tighten the sed extraction regex to match the validation pattern used for LATEST.
  4. (Nice-to-have) Enrich the PR-exists step summary with the existing PR URL and version.

Overall this is well-crafted automation. The security hardening (SHA pin, injection prevention, concurrency) is thorough, the logic is sound, and the two substantive issues from prior reviews have been addressed. The remaining items are all minor polish — the workflow is functionally correct as-is.


🔍 View AI decision process (logs available for 90 days)

📋 View memory system files loaded (click to expand)

What Amber Loaded for Code Review

Amber automatically loaded these repository standards from the memory system:

  1. CLAUDE.md - Master project instructions, development standards
  2. backend-development.md - Go backend, K8s integration patterns
  3. frontend-development.md - NextJS, Shadcn UI, React Query patterns
  4. security-standards.md - Auth, RBAC, token handling
  5. k8s-client-usage.md - User token vs service account patterns
  6. error-handling.md - Consistent error patterns
  7. react-query-usage.md - Data fetching patterns

Impact: This review used your repository's specific code quality standards, security patterns, and best practices from the memory system (PRs ambient-code#359, ambient-code#360) - not just generic code review guidelines.

Replace `pip install uv` with `astral-sh/setup-uv` (SHA-pinned v7.3.0)
which provides built-in caching keyed on uv.lock. This avoids
re-downloading uv and re-resolving the dependency graph on each run.

https://claude.ai/code/session_01AF1ro2VAMS7WSb7QayTetZ
@github-actions
Copy link

github-actions bot commented Feb 21, 2026

Claude Code Review

Summary

This PR adds a daily GitHub Actions workflow that polls PyPI for the latest claude-agent-sdk version and automatically opens a PR to bump the minimum version in pyproject.toml and regenerate uv.lock. This is CI/CD automation only — no backend, frontend, or operator code is changed, so patterns from .claude/context/ and .claude/patterns/ don't apply directly. The workflow shows solid security awareness and is generally well-constructed.


Issues by Severity

🚫 Blocker Issues

None.

🔴 Critical Issues

None.

🟡 Major Issues

1. Unverified action version comments

The entire value of SHA-pinning is the tamper-evident audit trail. If the version comment is wrong, reviewers cannot verify the pin without running git ls-remote. Both pinned actions should have their comments verified against actual release tags:

git ls-remote --tags https://github.com/actions/checkout v6.0.2
git ls-remote --tags https://github.com/astral-sh/setup-uv v7.3.0

A mismatch between comment and SHA undermines the supply chain hygiene rationale for pinning.

2. curl -sf silences diagnostic error output

LATEST=$(curl -sf --max-time 30 https://pypi.org/pypi/claude-agent-sdk/json | jq -r '.info.version')

The -s flag suppresses curl's own error messages. When PyPI is unreachable, DNS fails, or TLS errors occur, the only output is the generic "Failed to fetch latest version from PyPI" with no root cause. Dropping -s preserves diagnostic error reasons:

LATEST=$(curl -f --max-time 30 https://pypi.org/pypi/claude-agent-sdk/json | jq -r '.info.version')

🔵 Minor Issues

3. sed pattern assumes double-quote-wrapped dependency string

The sed substitution only matches "claude-agent-sdk>=..." with double quotes. If the pyproject.toml format ever changes, the pattern fails silently (caught by verification grep, but with a confusing error message). A comment documenting this assumption would prevent future confusion.

4. No retry on transient PyPI failures

A single attempt means a transient PyPI blip silently skips the day's check. The next scheduled run serves as implicit retry — acceptable — but a comment explaining this intentional design prevents it from looking like an oversight.

5. workflow_dispatch has no version override input

Maintainers can trigger manually but cannot specify a target version. An optional version input (validated with the same regex already in the workflow) would enable faster incident response:

workflow_dispatch:
  inputs:
    version:
      description: 'Force specific version (leave blank to use latest from PyPI)'
      required: false

Positive Highlights

  • SHA-pinned actions — Both actions/checkout and astral-sh/setup-uv are pinned to commit SHAs rather than mutable tags. Correct supply chain security posture.

  • Expression injection prevention — All steps.*.outputs.* values flow through env: blocks before reaching shell code, preventing injection if a malformed version string somehow passed validation.

  • sort -V for semver comparison — POSIX-portable and correct for version ordering (handles 0.0.9 vs 0.0.10 where lexicographic comparison fails).

  • Version format validation regex — Rejecting non-numeric version strings from PyPI before they reach sed or git commit is solid defensive practice.

  • Concurrency group with cancel-in-progress: false — Prevents parallel workflow races without silently dropping in-flight work.

  • uv.lock regeneration included — Lock file kept in sync with pyproject.toml in the same commit; prevents broken local dev environments after merge.

  • Comprehensive job summary — All four outcome states (up-to-date, PR exists, failure, PR created) are handled and surfaced.

  • GITHUB_TOKEN CI limitation documented — The generated PR body explains why pull_request workflows won't auto-trigger and offers BOT_TOKEN as an escape hatch.

  • Post-sed verification — The explicit grep check after substitution catches pattern mismatches before a malformed commit reaches the remote.

  • Diagnostic branch deletion — Uses 2>&1 || echo "..." rather than 2>/dev/null || true, preserving actionable output.


Recommendations

  1. Verify SHA/version comment pairs (Major Epic: MPP Deployment - Single-Namespace vTeam Implementation #1) — Run the git ls-remote commands above and update comments if they don't match. Low effort, high trust impact.

  2. Drop -s from curl (Major [Phase 1] Add SINGLE_NAMESPACE_MODE support to operator #2) — One-character change that immediately improves debuggability for the most common failure mode.

  3. Document the sed quoting assumption (Minor [Phase 1] Disable project creation endpoint in backend for single-namespace mode #3) — One comment line prevents a future maintainer from introducing a regression while "cleaning up" the pattern.

  4. Add workflow_dispatch version input (Minor [Phase 2] Convert ClusterRoles to namespace-scoped Roles #5) — Adds operational flexibility at low implementation cost.


Review performed by Claude Code against project standards in CLAUDE.md and .claude/context/.


🔍 View AI decision process (logs available for 90 days)

📋 View memory system files loaded (click to expand)

What Amber Loaded for Code Review

Amber automatically loaded these repository standards from the memory system:

  1. CLAUDE.md - Master project instructions, development standards
  2. backend-development.md - Go backend, K8s integration patterns
  3. frontend-development.md - NextJS, Shadcn UI, React Query patterns
  4. security-standards.md - Auth, RBAC, token handling
  5. k8s-client-usage.md - User token vs service account patterns
  6. error-handling.md - Consistent error patterns
  7. react-query-usage.md - Data fetching patterns

Impact: This review used your repository's specific code quality standards, security patterns, and best practices from the memory system (PRs ambient-code#359, ambient-code#360) - not just generic code review guidelines.

@jeremyeder
Copy link
Owner Author

This is ready to go. It opens a PR to bump the sdk if we are behind.

Alternative: let sdk version float and not intervene, let it break if its going to.

I actually prefer the latter, but let's do this first.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants