Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/workflows/strands-command.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ on:

jobs:
authorization-check:
if: startsWith(github.event.comment.body, '/strands') || github.event_name == 'workflow_dispatch'
# Exclude '/strands-ts' so strands-ts-command.yml handles it (the '/strands'
# prefix would otherwise match and fire both workflows on one comment).
if: (startsWith(github.event.comment.body, '/strands') && !startsWith(github.event.comment.body, '/strands-ts')) || github.event_name == 'workflow_dispatch'
name: Check access
permissions:
contents: read
Expand Down Expand Up @@ -82,7 +84,7 @@ jobs:
write_permission: 'false'

finalize:
if: always() && (startsWith(github.event.comment.body, '/strands') || github.event_name == 'workflow_dispatch')
if: always() && ((startsWith(github.event.comment.body, '/strands') && !startsWith(github.event.comment.body, '/strands-ts')) || github.event_name == 'workflow_dispatch')
needs: [setup-and-process, execute-readonly-agent]
permissions:
contents: write
Expand Down
98 changes: 98 additions & 0 deletions .github/workflows/strands-ts-command.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Multi-agent TypeScript PR reviewer, triggered by `/strands-ts <command>`.
# Mirrors strands-command.yml (the Python /strands handler) but invokes the
# strands-ts actions. Runs ALONGSIDE /strands; nothing is replaced.
#
# BLOCKED BY: strands-agents/devtools#68 — the strands-ts-* actions referenced
# below only exist on devtools@main AFTER that PR merges. Do not merge this
# until #68 is merged, or the runner/finalize steps will 404.
name: Strands-TS Command Handler

on:
issue_comment:
types: [created]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue: No concurrency group is defined, so multiple /strands-ts comments on the same PR (or a re-trigger before the prior run finishes) spawn overlapping reviewer runs that race on the strands-running label and post duplicate output.

Suggestion: Add a per-PR concurrency group, e.g.:

concurrency:
  group: strands-ts-${{ github.event.issue.number }}
  cancel-in-progress: false

Use cancel-in-progress: true if you'd rather the latest comment supersede an in-flight run.


# No workflow-level write perms: the read/write split is enforced per job so
# the agent job never holds a write-capable token.
permissions: {}

jobs:
authorization-check:
if: ${{ github.event.issue.pull_request && startsWith(github.event.comment.body, '/strands-ts') }}
name: Check access
permissions:
contents: read
runs-on: ubuntu-latest
outputs:
approval-env: ${{ steps.auth.outputs.approval-env }}
steps:
- name: Check Authorization
id: auth
uses: strands-agents/devtools/authorization-check@main
with:
username: ${{ github.event.comment.user.login || 'invalid' }}
allowed-roles: 'maintain,triage,write,admin'

mark-running:
needs: [authorization-check]
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue: mark-running holds issues: write + pull-requests: write but only declares needs: [authorization-check] with no environment: gate. In the approval-env pattern, authorization-check succeeds for everyone and routes unauthorized users into a protected environment requiring manual approval — that gate is what actually blocks them. execute-readonly-agent (L50) honors it via environment: ${{ needs.authorization-check.outputs.approval-env }}, but mark-running runs as soon as authorization-check completes, so an unauthorized commenter can still drive a write (add the strands-running label) before any approval.

In the Python workflow the label write lives in setup-and-process, which is behind environment: approval-env, so this gap is new here.

Suggestion: Add the same environment gate to mark-running:

  mark-running:
    needs: [authorization-check]
    environment: ${{ needs.authorization-check.outputs.approval-env }}

Impact is limited to a label toggle, but it's worth closing so the read/write split holds consistently.

steps:
- name: Add strands-running label
env:
GH_TOKEN: ${{ github.token }}
PR_NUM: ${{ github.event.issue.number }}
run: gh pr edit "$PR_NUM" --repo "${{ github.repository }}" --add-label strands-running || true

execute-readonly-agent:
needs: [authorization-check, mark-running]
environment: ${{ needs.authorization-check.outputs.approval-env }}
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
pull-requests: read
id-token: write # AWS OIDC role assumption only
steps:
- uses: actions/checkout@v4
- name: Resolve PR head SHA
id: pr
env:
GH_TOKEN: ${{ github.token }}
PR_NUM: ${{ github.event.issue.number }}
run: echo "sha=$(gh pr view "$PR_NUM" --json headRefOid -q .headRefOid)" >> "$GITHUB_OUTPUT"
- name: Run Strands-TS Agent
uses: strands-agents/devtools/strands-command/actions/strands-ts-runner@main
with:
command: ${{ github.event.comment.body }}
pr_number: ${{ github.event.issue.number }}
pr_head_sha: ${{ steps.pr.outputs.sha }}
aws_role_arn: ${{ secrets.AWS_ROLE_ARN }}
agents_config: ${{ vars.STRANDS_TS_AGENTS || '' }}

finalize:
needs: [execute-readonly-agent]
if: ${{ needs.execute-readonly-agent.result == 'success' }}
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write # the ONLY job that can write; replays vetted artifact ops
steps:
- uses: actions/checkout@v4
- name: Replay deferred writes
uses: strands-agents/devtools/strands-command/actions/strands-ts-finalize@main

clear-running:
needs: [mark-running, execute-readonly-agent, finalize]
if: ${{ always() && needs.mark-running.result == 'success' }}
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- name: Remove strands-running label
env:
GH_TOKEN: ${{ github.token }}
PR_NUM: ${{ github.event.issue.number }}
run: gh pr edit "$PR_NUM" --repo "${{ github.repository }}" --remove-label strands-running || true
Loading