From 529b25c3e45ddeafdd3f64d2f553c2191d2d7c44 Mon Sep 17 00:00:00 2001 From: Damien Daspit Date: Mon, 5 Oct 2026 15:53:57 -0400 Subject: [PATCH 1/2] Show which tool calls the @claude workflow denied On #390, Claude could not run the tests or local_check.sh, although both are allowed. The action hides Claude's output, so the log only gave a count of 3 denials. A new step prints the denied calls from the execution file. Allowed commands match by prefix, so the prompt now asks Claude to run the checks from the repository root without cd or a wrapper. tail and head are allowed for trimming output. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/claude.yml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 4fcce886..90756325 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -93,7 +93,18 @@ jobs: # appended prompt has Claude open the pull request itself. claude_args: >- --add-dir ../machine - --allowedTools "Bash(gh pr create:*),Bash(gh pr view:*),Bash(gh pr diff:*),Bash(gh issue view:*),Bash(git log:*),Bash(git blame:*),Bash(git show:*),Bash(git diff:*),Bash(git status:*),Bash(git -C ../machine show:*),Bash(git -C ../machine cat-file:*),Bash(git -C ../machine log:*),Bash(git -C ../machine blame:*),Bash(poetry run:*),Bash(./local_check.sh:*)" - --append-system-prompt "When invoked on an issue and you change code, open the pull request yourself once your commits are pushed: gh pr create --base main --head . Post its link in your comment in place of a Create a PR link. Write the title and body with the pr-authoring skill, and put Closes # in the body. Before opening it, run ./local_check.sh --agent-strict and report its result in the body. Dependencies are already installed, and you work on the branch this action created: where a skill such as port-pr says to install, create or switch branches, or push, commit on the current branch and push it the way these instructions say. When the issue is labeled porting, port it with the port-pr skill." + --allowedTools "Bash(gh pr create:*),Bash(gh pr view:*),Bash(gh pr diff:*),Bash(gh issue view:*),Bash(git log:*),Bash(git blame:*),Bash(git show:*),Bash(git diff:*),Bash(git status:*),Bash(git -C ../machine show:*),Bash(git -C ../machine cat-file:*),Bash(git -C ../machine log:*),Bash(git -C ../machine blame:*),Bash(poetry run:*),Bash(./local_check.sh:*),Bash(tail:*),Bash(head:*)" + --append-system-prompt "When invoked on an issue and you change code, open the pull request yourself once your commits are pushed: gh pr create --base main --head . Post its link in your comment in place of a Create a PR link. Write the title and body with the pr-authoring skill, and put Closes # in the body. Before opening it, run ./local_check.sh --agent-strict and report its result in the body. Dependencies are already installed, and you work on the branch this action created: where a skill such as port-pr says to install, create or switch branches, or push, commit on the current branch and push it the way these instructions say. Allowed commands match by prefix, so run poetry run and ./local_check.sh from the repository root as they are, not after cd or inside a wrapper such as timeout. When the issue is labeled porting, port it with the port-pr skill." # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md # or https://code.claude.com/docs/en/cli-reference for available options + + # The action hides Claude's output, so the log does not say which calls were denied. + # The denied calls alone name the allowedTools rule a run was missing. + - name: Show denied tool calls + if: always() && steps.claude.outputs.execution_file != '' + env: + EXECUTION_FILE: ${{ steps.claude.outputs.execution_file }} + run: >- + jq -r '.[] | select(.type == "result") | .permission_denials[]? + | "\(.tool_name): \(.tool_input.command // (.tool_input | tostring))"[:300]' + "$EXECUTION_FILE" From 154b3b0084ab4af14e89036a91aca019436895ea Mon Sep 17 00:00:00 2001 From: Damien Daspit Date: Tue, 6 Oct 2026 10:51:36 -0400 Subject: [PATCH 2/2] Print denied calls safely and keep the step from failing the job A denied multi-line command printed raw, so a line starting with "::" could issue a workflow command, and a denied Write or Edit put file content in the public log. The step now prints only the command, path, URL or pattern, encoded as one JSON line. It can no longer fail a run that Claude finished. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/claude.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 90756325..6895c9fe 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -99,12 +99,15 @@ jobs: # or https://code.claude.com/docs/en/cli-reference for available options # The action hides Claude's output, so the log does not say which calls were denied. - # The denied calls alone name the allowedTools rule a run was missing. + # Only the command or target is printed, never file content, and @json keeps it on one + # line so a denied command cannot issue a "::" workflow command. - name: Show denied tool calls if: always() && steps.claude.outputs.execution_file != '' + continue-on-error: true env: EXECUTION_FILE: ${{ steps.claude.outputs.execution_file }} run: >- jq -r '.[] | select(.type == "result") | .permission_denials[]? - | "\(.tool_name): \(.tool_input.command // (.tool_input | tostring))"[:300]' + | "\(.tool_name): \((.tool_input.command? // .tool_input.file_path? // .tool_input.url? + // .tool_input.pattern? // "") | @json | .[:300])"' "$EXECUTION_FILE"