Skip to content

Show which tool calls the @claude workflow denied - #396

Merged
ddaspit merged 2 commits into
mainfrom
ddaspit/claude-show-denials
Oct 6, 2026
Merged

ddaspit merged 2 commits into
mainfrom
ddaspit/claude-show-denials

Conversation

@ddaspit

@ddaspit ddaspit commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Quick summary

The @claude workflow log now lists the tool calls that were denied, not just how many. Claude is also told how to run the checks so they match the allowed commands. Only claude.yml changes.

Where to look

On #390, Claude could not run the tests, black, flake8 or ./local_check.sh --agent-strict. The run already allowed Bash(poetry run:*) and Bash(./local_check.sh:*), so the calls must have taken a form those rules do not match, such as a pipe, a cd, or a wrapper like timeout. The action hides Claude's output, so the log only says permission_denials_count: 3.

  • A new step reads the action's execution_file and prints each denied call's tool and command, cut at 300 characters. It does not turn on show_full_output, which would put tool output in the log of a public repo.
  • The appended prompt says that allowed commands match by prefix, and asks Claude to run poetry run and ./local_check.sh from the repository root, without cd or a wrapper.
  • tail and head are allowed, so Claude can trim test output in a pipe. Both only read.

Validation

  • Parsed .github/workflows/claude.yml with PyYAML. It parsed.
  • git diff --check -- clean.
  • I did not test the jq filter, because jq is not installed here. The ubuntu runners include it.
  • I did not run ./local_check.sh. This PR only changes a workflow file.
  • None of this can be verified until the workflow runs after merge. The next run that has a denial will show it.

🤖 Generated with Claude Code


This change is Reviewable

@codecov-commenter

codecov-commenter commented Oct 5, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.07%. Comparing base (35c9445) to head (154b3b0).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #396   +/-   ##
=======================================
  Coverage   92.07%   92.07%           
=======================================
  Files         394      394           
  Lines       24896    24896           
=======================================
  Hits        22922    22922           
  Misses       1974     1974           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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 <noreply@anthropic.com>
@ddaspit
ddaspit force-pushed the ddaspit/claude-show-denials branch from bce79d0 to 529b25c Compare October 6, 2026 14:39
Comment thread .github/workflows/claude.yml Resolved
Comment thread .github/workflows/claude.yml Resolved
Comment thread .github/workflows/claude.yml Resolved
Comment thread .github/workflows/claude.yml Resolved
@claude

This comment has been minimized.

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 <noreply@anthropic.com>
@claude

claude Bot commented Oct 6, 2026

Copy link
Copy Markdown
Contributor
  1. Verdict: approve. All earlier findings are settled and the new commit adds no new ones.
  2. Most important: nothing open. The step at .github/workflows/claude.yml:109 now prints one escaped line per denial and cannot fail the job.
  3. Counts: 0 Critical, 0 Important, 0 Low open.
  4. Ran: read git diff 529b25c 154b3b0 (compare status ahead). Ran the step's filter with jq -n on inline samples: a Bash command containing a newline and ::error::, a Write with content, WebFetch, Grep, a string tool_input, a tool with none of the keys, and a 400-character command. Each printed one line, content was never printed, the cases with no matching key printed "", and the long command was cut at 300 characters. Did not run ./local_check.sh: only a workflow file changes, and the script does not check it.
  5. Not verified: the step on a real run's execution file, and how Claude Code matches cd, timeout, and pipes against allowed tools.

Public API, optional dependency, published-wheel surface, sillsdev/machine parity: None verified changed. CI only.

Findings: F1 addressed, F2 addressed, F3 addressed, F4 withdrawn.

Reviewed at 154b3b0

@ddaspit ddaspit added the no porting No porting issue is created in the other repository when this PR is merged. label Oct 6, 2026
@ddaspit
ddaspit merged commit cc99576 into main Oct 6, 2026
35 of 36 checks passed
@ddaspit
ddaspit deleted the ddaspit/claude-show-denials branch October 6, 2026 15:46
ddaspit added a commit to sillsdev/machine that referenced this pull request Oct 6, 2026
The action hides Claude's output, so the log only gave a count of denied tool
calls. A new step prints each denied call's tool and command. Claude is also
told that allowed commands match by prefix, so it runs dotnet and
./local_check.sh from the repository root without cd or a wrapper. tail and
head are allowed so it can trim test output.

Ports sillsdev/machine.py#396.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ddaspit added a commit to sillsdev/machine that referenced this pull request Oct 6, 2026
The action hides Claude's output, so the log only gave a count of denied tool
calls. A new step prints each denied call's tool and command. Claude is also
told that allowed commands match by prefix, so it runs dotnet and
./local_check.sh from the repository root without cd or a wrapper. tail and
head are allowed so it can trim test output.

Ports sillsdev/machine.py#396.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no porting No porting issue is created in the other repository when this PR is merged.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants