Skip to content
Merged
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
4 changes: 2 additions & 2 deletions .github/workflows/tend-ci-fix.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by tend 0.2.13. Regenerate with: uvx tend@latest init
# Generated by tend 0.2.15. Regenerate with: uvx tend@latest init
#
# Do not edit this file directly — it will be overwritten on regeneration.
# To change this workflow, edit .config/tend.yaml. To change what the agent
Expand Down Expand Up @@ -42,7 +42,7 @@ jobs:
fetch-tags: true
token: ${{ secrets.TEND_BOT_TOKEN }}

- uses: max-sixty/tend/claude@0.2.13
- uses: max-sixty/tend/claude@0.2.15
with:
github_token: ${{ secrets.TEND_BOT_TOKEN }}
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tend-mention-relay.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by tend 0.2.13. Regenerate with: uvx tend@latest init
# Generated by tend 0.2.15. Regenerate with: uvx tend@latest init
#
# Do not edit this file directly — it will be overwritten on regeneration.
# To change this workflow, edit .config/tend.yaml. To change what the agent
Expand Down
20 changes: 11 additions & 9 deletions .github/workflows/tend-mention.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by tend 0.2.13. Regenerate with: uvx tend@latest init
# Generated by tend 0.2.15. Regenerate with: uvx tend@latest init
#
# Do not edit this file directly — it will be overwritten on regeneration.
# To change this workflow, edit .config/tend.yaml. To change what the agent
Expand Down Expand Up @@ -50,7 +50,7 @@ jobs:
url: ${{ steps.check.outputs.url }}
ts: ${{ steps.check.outputs.ts }}
steps:
- uses: astral-sh/setup-uv@v10.1.0
- uses: astral-sh/setup-uv@v10.2.0
id: tend_uv
env:
UV_NO_MODIFY_PATH: "1"
Expand Down Expand Up @@ -326,12 +326,8 @@ jobs:
|| format('pulls/comments/{0}', github.event.client_payload.id) }}
GITHUB_TOKEN: ${{ secrets.TEND_BOT_TOKEN }}

- uses: actions/checkout@v7
with:
fetch-depth: 0
fetch-tags: true
token: ${{ secrets.TEND_BOT_TOKEN }}

# Before checkout and `setup:`, so the delay measures the wait for this
# job to start rather than the time its setup takes.
- name: Compute queue delay
id: delay
run: |
Expand All @@ -346,7 +342,13 @@ jobs:
# the API record — the dispatch payload never carries one to spoof.
EVENT_TS: ${{ github.event.comment.updated_at || needs.verify.outputs.ts || github.event.issue.updated_at }}

- uses: max-sixty/tend/claude@0.2.13
- uses: actions/checkout@v7
with:
fetch-depth: 0
fetch-tags: true
token: ${{ secrets.TEND_BOT_TOKEN }}

- uses: max-sixty/tend/claude@0.2.15
with:
github_token: ${{ secrets.TEND_BOT_TOKEN }}
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/tend-nightly.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by tend 0.2.13. Regenerate with: uvx tend@latest init
# Generated by tend 0.2.15. Regenerate with: uvx tend@latest init
#
# Do not edit this file directly — it will be overwritten on regeneration.
# To change this workflow, edit .config/tend.yaml. To change what the agent
Expand Down Expand Up @@ -33,7 +33,7 @@ jobs:
fetch-tags: true
token: ${{ secrets.TEND_BOT_TOKEN }}

- uses: max-sixty/tend/claude@0.2.13
- uses: max-sixty/tend/claude@0.2.15
with:
github_token: ${{ secrets.TEND_BOT_TOKEN }}
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/tend-notifications.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by tend 0.2.13. Regenerate with: uvx tend@latest init
# Generated by tend 0.2.15. Regenerate with: uvx tend@latest init
#
# Do not edit this file directly — it will be overwritten on regeneration.
# To change this workflow, edit .config/tend.yaml. To change what the agent
Expand Down Expand Up @@ -29,7 +29,7 @@ jobs:
actions: read
issues: write
steps:
- uses: astral-sh/setup-uv@v10.1.0
- uses: astral-sh/setup-uv@v10.2.0
id: tend_uv
env:
UV_NO_MODIFY_PATH: "1"
Expand Down Expand Up @@ -244,7 +244,7 @@ jobs:
fetch-depth: 0
fetch-tags: true
token: ${{ secrets.TEND_BOT_TOKEN }}
- uses: max-sixty/tend/claude@0.2.13
- uses: max-sixty/tend/claude@0.2.15
if: steps.check.outputs.count != '0' || steps.check.outputs.conflict_count != '0' || github.event_name == 'workflow_dispatch'
with:
github_token: ${{ secrets.TEND_BOT_TOKEN }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/tend-review-runs.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by tend 0.2.13. Regenerate with: uvx tend@latest init
# Generated by tend 0.2.15. Regenerate with: uvx tend@latest init
#
# Do not edit this file directly — it will be overwritten on regeneration.
# To change this workflow, edit .config/tend.yaml. To change what the agent
Expand Down Expand Up @@ -33,7 +33,7 @@ jobs:
fetch-tags: true
token: ${{ secrets.TEND_BOT_TOKEN }}

- uses: max-sixty/tend/claude@0.2.13
- uses: max-sixty/tend/claude@0.2.15
with:
github_token: ${{ secrets.TEND_BOT_TOKEN }}
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/tend-review.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by tend 0.2.13. Regenerate with: uvx tend@latest init
# Generated by tend 0.2.15. Regenerate with: uvx tend@latest init
#
# Do not edit this file directly — it will be overwritten on regeneration.
# To change this workflow, edit .config/tend.yaml. To change what the agent
Expand Down Expand Up @@ -42,16 +42,16 @@ jobs:
TARGET: issues/${{ github.event.pull_request.number }}
GITHUB_TOKEN: ${{ secrets.TEND_BOT_TOKEN }}

# The runner checkout remains on the reviewed base tree for local setup
# actions and their POST chains. The harness creates and selects the PR
# topology in an independent disposable clone.
# The runner checkout stays on the reviewed base tree for `setup:` and
# local actions' POST chains; the harness moves the agent's view of it to
# the PR's topology.
- uses: actions/checkout@v7
with:
fetch-depth: 0
fetch-tags: true
token: ${{ secrets.TEND_BOT_TOKEN }}

- uses: max-sixty/tend/claude@0.2.13
- uses: max-sixty/tend/claude@0.2.15
with:
github_token: ${{ secrets.TEND_BOT_TOKEN }}
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/tend-triage.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by tend 0.2.13. Regenerate with: uvx tend@latest init
# Generated by tend 0.2.15. Regenerate with: uvx tend@latest init
#
# Do not edit this file directly — it will be overwritten on regeneration.
# To change this workflow, edit .config/tend.yaml. To change what the agent
Expand Down Expand Up @@ -45,7 +45,7 @@ jobs:
fetch-tags: true
token: ${{ secrets.TEND_BOT_TOKEN }}

- uses: max-sixty/tend/claude@0.2.13
- uses: max-sixty/tend/claude@0.2.15
with:
github_token: ${{ secrets.TEND_BOT_TOKEN }}
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/tend-weekly.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by tend 0.2.13. Regenerate with: uvx tend@latest init
# Generated by tend 0.2.15. Regenerate with: uvx tend@latest init
#
# Do not edit this file directly — it will be overwritten on regeneration.
# To change this workflow, edit .config/tend.yaml. To change what the agent
Expand Down Expand Up @@ -33,7 +33,7 @@ jobs:
fetch-tags: true
token: ${{ secrets.TEND_BOT_TOKEN }}

- uses: max-sixty/tend/claude@0.2.13
- uses: max-sixty/tend/claude@0.2.15
with:
github_token: ${{ secrets.TEND_BOT_TOKEN }}
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
Expand Down
2 changes: 1 addition & 1 deletion docs/specs/security-ci.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ This repository runs the [tend](https://github.com/max-sixty/tend) agent harness

**Prompt-injection through user-supplied content.** The harness reads PR descriptions, code diffs, issue text, comments, and CI logs — all attacker-influenceable. **Assume a malicious prompt can push a workflow that sends a repo-level secret to an external URL**: admin-gated release paths stay sealed, but a workflow on a bot-pushed feature branch still executes with repo-level secrets in scope.

**Instruction files are part of that surface.** On a fork PR the privileged `pull_request_target` runner workspace holds the base tree; the attacker-controlled PR tree exists only in the harness's own disposable clone, and that is where the *project instructions* Claude Code loads (`CLAUDE.md`, `AGENTS.md`, `.claude/`, `.mcp.json`) come from. **Must revert those paths from the reviewed base branch before the agent starts**, so instructions come from code a maintainer merged — tend's `shared/steps/restore-sensitive-config.sh` does it. **That control's completeness is a property of the pinned upstream version, not of anything in this repo** — hence the `0.1.19` floor below (rationale).
**Instruction files are part of that surface.** On a fork PR the privileged `pull_request_target` runner workspace holds the base tree; the attacker-controlled PR tree exists only in the agent's copy-on-write view, and that is where the *project instructions* Claude Code loads (`CLAUDE.md`, `AGENTS.md`, `.claude/`, `.mcp.json`) come from. **Must revert those paths from the reviewed base branch before the agent starts**, so instructions come from code a maintainer merged — tend's `shared/steps/restore-sensitive-config.sh` does it. **That control's completeness is a property of the pinned upstream version, not of anything in this repo** — hence the `0.1.19` floor below (rationale).

**Credential isolation bounds an injection.** The agent runs as a separate, non-sudo sandbox user behind a local credential-injecting proxy. **`TEND_BOT_TOKEN` and the Anthropic credential must live only in that proxy — never in the agent's environment, its disk, or `.git/config`** — setup strips the credential `actions/checkout` persists there, so an injection can make the bot *act* within its permissions, never read a token value out (rationale).

Expand Down
2 changes: 1 addition & 1 deletion docs/specs/security-ci.rationale.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

**Why instruction files are a class of their own.** They are not read as data the way a diff is; Claude Code loads them as authoritative guidance, which is what makes a fork PR's copy of them a different class of input from the fork's code.

**The `0.1.18` gap, reported from this audit and now fixed.** At the previously pinned `0.1.18` the revert list was a flat, root-relative `SENSITIVE` array naming `CLAUDE.md` but no `AGENTS.md` at all — and this repo keeps its instructions in `AGENTS.md` with `CLAUDE.md` as a one-line `@AGENTS.md` pointer, so the control reverted a pointer and left the content it pointed at attacker-controlled. The fix ([max-sixty/tend#1005](https://github.com/max-sixty/tend/pull/1005), merged 2026-08-22, released in `0.1.19` on 2026-08-26) replaces that list with pathspec globs — `':(glob)**/AGENTS.md'`, `':(glob)**/CLAUDE.md'`, `':(glob)**/.claude/**'` — which `restore-sensitive-config.sh` passes to `pin_to_base`, covering every depth rather than a hand-enumerated set of root paths. `0.1.19` remains the minimum security floor; the version each workflow actually runs is the one in its own generated header, `0.2.13` at the September 2026 inspection.
**The `0.1.18` gap, reported from this audit and now fixed.** At the previously pinned `0.1.18` the revert list was a flat, root-relative `SENSITIVE` array naming `CLAUDE.md` but no `AGENTS.md` at all — and this repo keeps its instructions in `AGENTS.md` with `CLAUDE.md` as a one-line `@AGENTS.md` pointer, so the control reverted a pointer and left the content it pointed at attacker-controlled. The fix ([max-sixty/tend#1005](https://github.com/max-sixty/tend/pull/1005), merged 2026-08-22, released in `0.1.19` on 2026-08-26) replaces that list with pathspec globs — `':(glob)**/AGENTS.md'`, `':(glob)**/CLAUDE.md'`, `':(glob)**/.claude/**'` — which `restore-sensitive-config.sh` passes to `pin_to_base`, covering every depth rather than a hand-enumerated set of root paths. `0.1.19` remains the minimum security floor; the version each workflow actually runs is the one in its own generated header, `0.2.15` at the September 2026 inspection.

**The local remedy if it ever regresses.** The nightly regen overwrites the *workflow*, not this repository's instruction files, so moving the instruction body into `CLAUDE.md` and dropping the pointer would close it with no upstream dependency, at the cost of the filename convention other agent harnesses read.

Expand Down
Loading