Skip to content

chore(release): prepare 0.28.0#43

Merged
elkaix merged 8 commits into
mainfrom
release/0.28.0
Jun 1, 2026
Merged

chore(release): prepare 0.28.0#43
elkaix merged 8 commits into
mainfrom
release/0.28.0

Conversation

@elkaix
Copy link
Copy Markdown
Contributor

@elkaix elkaix commented Jun 1, 2026

Related Issue

Resolve #(issue_number)

Description

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked the related issue, if any.
  • I have added tests that prove my fix is effective or that my feature works.
  • I have run make gen-changelog to update the changelog.
  • I have run make gen-docs to update the user documentation.

Summary by CodeRabbit

  • Documentation
    • Installer docs updated to reference v0.28.0; agent/workflow docs and changelog clarify AGENTS.md precedence (ignore legacy dotfile) and document the new judge stage and code-quality defaults.
  • New Features
    • Added a built-in "judge" subagent as a final independent quality gate with a structured PASS/NEEDS_WORK/BLOCKED verdict contract.
  • Bug Fixes / Security
    • Read-only/review profiles now block common network-capable shell commands to prevent web-tool bypass.
  • Chores
    • Updated repository code-ownership routing for reviews.

elkaix added 3 commits May 31, 2026 23:20
Bundles the GitHub org migration (TechMatrix-labs -> Pythoughts-labs)
with the 0.28.0 release prep.

Org migration:
- Repoint all GitHub URLs, install scripts, CI workflow targets
  (homebrew tap, scoop bucket, pythinker-home dispatch), and the
  default /feedback repository to github.com/Pythoughts-labs/pythinker-code.
- Add the previous owner to the legacy feedback-repo migration set so
  existing configs auto-update to the new default (with a covering test).

Release 0.28.0:
- Bump version 0.27.0 -> 0.28.0 (pyproject.toml, uv.lock).
- Promote the Unreleased changelog into a dated 0.28.0 block across
  CHANGELOG.md and docs, mirror the full bullet set, and record the
  org move; add the 0.28.0 breaking-changes entry (none).
- Refresh the README "What's New" section and bump release-asset
  filenames / download URLs to 0.28.0.
Addresses CodeRabbit: the local build command showed 0.27.0 while its
own output listing and the rest of the release docs use 0.28.0.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 1, 2026

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a new built-in judge subagent (config, prompt contract, allowlist/exclude rules), updates execution profiles and permission checks to block network-capable shell commands in read-only/verify profiles, updates docs/tests/packaging to include judge, and applies small repo metadata edits (CODEOWNERS, installer README, changelog).

Changes

Judge subagent feature

Layer / File(s) Summary
Agent configs and authored docs
src/pythinker_code/agents/default/agent.yaml, src/pythinker_code/agents/default/judge.yaml, src/pythinker_code/agents/default/plan.yaml, src/pythinker_code/agents/default/system.md, src/pythinker_code/tools/agent/description.md, AGENTS.md, docs/en/customization/agents.md
Add judge subagent declaration and full judge.yaml definition; update plan/system docs, AGENTS.md, and agent tool description to document the final LLM judge gate, response contract, and allowed/excluded tools; adjust AGENTS.md discovery wording.
Permission rules and execution profiles
src/pythinker_code/execution_profiles.py, src/pythinker_code/soul/permission.py
Add judge to allowed subagent types for profiles and extend shell-command gating to classify and block network-capable CLIs and network-performing git subcommands in read-only/verify-like profiles.
Runner minimums, packaging, changelog, installer README
src/pythinker_code/subagents/runner.py, tests/utils/test_pyinstaller_utils.py, CHANGELOG.md, packages/linux-installer/README.md
Set judge summary minimum length; include judge.yaml in PyInstaller datas; update changelog entries about AGENTS.md discovery and network-shell blocking; bump linux-installer README example build command to 0.28.0.
Tests, discovery behavior, and snapshots
tests/*, src/pythinker_code/soul/agent.py
Update tests and snapshots to expect judge; add tests to verify .pythinker/AGENTS.md is ignored and update load/discovery tests; extend permission/profile tests to cover network-shell denial cases.

Repository metadata updates

Layer / File(s) Summary
CODEOWNERS ownership reassignments
.github/CODEOWNERS
Reassign dependency, telemetry, and CI/workflow path owners to @elkaix.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

enhancement

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning PR description is a template with all placeholders unfilled; no actual implementation details, related issue link, or checklist items completed. Fill in the Description section with actual changes made (judge subagent, network shell blocking, CODEOWNERS update, etc.) and indicate which checklist items apply to this release PR.
Docstring Coverage ⚠️ Warning Docstring coverage is 55.00% which is insufficient. The required threshold is 70.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed Title follows conventional commits format with valid type 'chore', scope 'release', and clear description of preparing version 0.28.0.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch release/0.28.0

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/linux-installer/README.md (1)

47-49: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update stale tarball example version to 0.28.0.

This section still shows pythinker-0.27.0-...tar.gz, which conflicts with the 0.28.0 release docs above and can mislead users copying artifact names.

Suggested fix
- target-triple naming (e.g. `pythinker-0.27.0-x86_64-unknown-linux-gnu.tar.gz`).
+ target-triple naming (e.g. `pythinker-0.28.0-x86_64-unknown-linux-gnu.tar.gz`).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/linux-installer/README.md` around lines 47 - 49, The README example
references a stale tarball name
"pythinker-0.27.0-x86_64-unknown-linux-gnu.tar.gz"; update that string to
"pythinker-0.28.0-x86_64-unknown-linux-gnu.tar.gz" so the example matches the
0.28.0 release docs and the artifact produced by the release-pythinker-cli.yml
workflow (and verify scripts/install-native.sh references the same artifact name
if present). Locate the example text in packages/linux-installer/README.md and
replace the version substring, ensuring the naming pattern remains cargo-dist
target-triple style.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/linux-installer/README.md`:
- Around line 47-49: The README example references a stale tarball name
"pythinker-0.27.0-x86_64-unknown-linux-gnu.tar.gz"; update that string to
"pythinker-0.28.0-x86_64-unknown-linux-gnu.tar.gz" so the example matches the
0.28.0 release docs and the artifact produced by the release-pythinker-cli.yml
workflow (and verify scripts/install-native.sh references the same artifact name
if present). Locate the example text in packages/linux-installer/README.md and
replace the version substring, ensuring the naming pattern remains cargo-dist
target-triple style.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8713513c-27fc-42d6-ba5e-9f67f9565bc4

📥 Commits

Reviewing files that changed from the base of the PR and between 5fb054c and 21153d6.

📒 Files selected for processing (1)
  • packages/linux-installer/README.md

Add a read-only LLM-as-judge subagent that independently gates
high-stakes deliverables before they reach the user, wired into the
agent roster, execution profiles, permission profiles, and the
subagent runner.

Redesign the default prompts for clarity and to cut wasted work:

- AGENTS.md guidance now states the root-to-working-dir files are
  pre-merged and authoritative, and to search only directories below
  the working dir, which stops redundant AGENTS.md discovery.
- The judge gate is scoped to high-stakes or hard-to-reverse
  deliverables and framed as one cheap evidence-gating pass.
- The judge prompt uses a criteria-based rubric that defaults to
  NEEDS_WORK when a load-bearing claim is unsupported.
- Stop discovering .pythinker/AGENTS.md; only AGENTS.md/agents.md from
  the project root down to the working directory are merged.
- Trim off-voice boilerplate from the code-quality defaults.

Update inline-snapshot fixtures to match.
@elkaix elkaix changed the title Release/0.28.0 chore(release): prepare 0.28.0 Jun 1, 2026
@elkaix
Copy link
Copy Markdown
Contributor Author

elkaix commented Jun 1, 2026

This release branch now also includes the following, cherry-picked from feat/judge-subagent-prompt-redesign (all local tests green — 4089 passed):

  • feat(agents): read-only judge LLM-as-judge subagent + default-prompt redesign (pre-merged AGENTS.md semantics that stop redundant discovery, high-stakes-scoped judge gate, criteria-based rubric, .pythinker/AGENTS.md removed from instruction discovery).
  • fix(security): read-only/review/verify permission profiles now block network shell commands (curl/wget/ssh/git-fetch), closing a Shell-based bypass of those subagents' no-web-tools intent.
  • chore: valid CODEOWNERS owner (org handle was invalid) + Unreleased changelog notes.

The previously-failing pr-title-checker was due to the non-conventional PR title; addressed by the retitle.

elkaix added 2 commits June 1, 2026 00:46
The read_only/plan/review/verify permission profiles excluded the web
tools but still allowed Shell, so curl/wget/ssh/git-fetch could reach
the network and bypass a read-only subagent's no-web-tools intent.

Classify network CLIs and git-network subcommands as blocked in those
profiles. Read-only working-tree git (diff/log/show/status) stays
allowed so judge and verifier can inspect changes; script interpreters
were already treated as mutating.
An organization handle is not a valid CODEOWNERS owner, so review
routing did not fire; use the maintainer account instead.

Record the .pythinker/AGENTS.md removal (with migration guidance) and
the network-shell hardening under the Unreleased changelog section.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/CODEOWNERS:
- Line 11: Replace single-person ownership entries in the CODEOWNERS file
(currently assigning `@mohamed-elkholy95` to critical paths and self-owning the
CODEOWNERS file) with a GitHub team to avoid a single point of failure: create
or use an existing org team such as `@Pythoughts-labs/maintainers` or
`@Pythoughts-labs/infra`, add multiple responsible members to that team, and
update the owner lines that reference `@mohamed-elkholy95` (including the entry
that gives ownership of the CODEOWNERS file) to reference the team instead so
critical surfaces (dependency files, telemetry, CI workflows, and the CODEOWNERS
file) require team review rather than a single individual.
- Line 11: The CODEOWNERS entry currently lists an invalid GitHub handle
"`@mohamed-elkholy95`" and concentrates many critical paths under a single
individual; update the .github/CODEOWNERS by replacing the invalid owner with a
valid GitHub team (e.g., a repo or org team like "org-name/team-name") and
distribute ownership of critical patterns (default lines, dependency surfaces,
telemetry, CI, and CODEOWNERS) across the appropriate teams instead of one user;
ensure you remove any self-owning reference to the .github directory and verify
the new team handles resolve on GitHub so review routing works correctly.

In `@docs/en/customization/agents.md`:
- Around line 167-180: Update the Agent tool description to reflect the full set
of built-in subagents (coder, implementer, explore, plan, review, code-reviewer,
security-reviewer, debugger, verifier, judge) and their tool policies; replace
the previous "only three built-ins" wording in the Agent section with a brief
list of these subagents and note which ones allow write tools (coder,
implementer) versus read-only or shell-only variants (explore, plan, review,
code-reviewer, security-reviewer, debugger, verifier, judge) so the Agent
documentation aligns with the table of built-ins above.

In `@src/pythinker_code/soul/permission.py`:
- Around line 361-362: The current check uses the immediate token in subcommand
to detect git network usage (if subcommand in _GIT_NETWORK) but this misses
cases where git flags/options (e.g., -c key=val, --option) appear before the
true subcommand; update the parsing logic where subcommand is evaluated so you
iterate over the git arguments to find the first non-option token (skip tokens
starting with '-' and treat '-c' as consuming its next value, honor '--' to end
options), then test that resolved token against _GIT_NETWORK and return
f"network access via git {resolved_subcommand}" when matched; reference the
existing subcommand variable and _GIT_NETWORK constant in permission.py to
locate and replace the simplistic check.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0c6bfa32-ee34-4723-ae7c-7b812b72dbdf

📥 Commits

Reviewing files that changed from the base of the PR and between 21153d6 and 96d266b.

📒 Files selected for processing (20)
  • .github/CODEOWNERS
  • AGENTS.md
  • CHANGELOG.md
  • docs/en/customization/agents.md
  • src/pythinker_code/agents/default/agent.yaml
  • src/pythinker_code/agents/default/judge.yaml
  • src/pythinker_code/agents/default/plan.yaml
  • src/pythinker_code/agents/default/system.md
  • src/pythinker_code/execution_profiles.py
  • src/pythinker_code/soul/agent.py
  • src/pythinker_code/soul/permission.py
  • src/pythinker_code/subagents/runner.py
  • src/pythinker_code/tools/agent/description.md
  • tests/core/test_agent_spec.py
  • tests/core/test_default_agent.py
  • tests/core/test_load_agent.py
  • tests/core/test_load_agents_md.py
  • tests/core/test_permission_profiles.py
  • tests/tools/test_tool_descriptions.py
  • tests/utils/test_pyinstaller_utils.py

Comment thread .github/CODEOWNERS Outdated
Comment thread docs/en/customization/agents.md
Comment thread src/pythinker_code/soul/permission.py
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
.github/CODEOWNERS (1)

11-11: ⚠️ Potential issue | 🔴 Critical

Past findings remain unaddressed.

The critical and major issues flagged in previous review comments are still present:

  1. Critical: @mohamed-elkholy95 does not exist on GitHub (verified 404). CODEOWNERS routing will fail entirely.
  2. Major: Single owner assignment creates operational bottleneck for dependency updates, telemetry changes, CI workflows, and CODEOWNERS itself.

Recommendation remains: Replace with a valid GitHub team handle (e.g., @Pythoughts-labs/maintainers) for redundancy and functional review routing.

Also applies to: 14-21, 24-25, 29-30

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/CODEOWNERS at line 11, Replace the invalid GitHub user handle
`@mohamed-elkholy95` in the CODEOWNERS entries with a valid team handle (for
example `@Pythoughts-labs/maintainers`) and add at least one additional owner per
path to avoid a single-owner bottleneck; update every CODEOWNERS entry that
references `@mohamed-elkholy95` to use the team handle and multiple maintainers,
and ensure commit message explains the replacement so review routing and
ownership of dependency/CI/telemetry changes works correctly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In @.github/CODEOWNERS:
- Line 11: Replace the invalid GitHub user handle `@mohamed-elkholy95` in the
CODEOWNERS entries with a valid team handle (for example
`@Pythoughts-labs/maintainers`) and add at least one additional owner per path to
avoid a single-owner bottleneck; update every CODEOWNERS entry that references
`@mohamed-elkholy95` to use the team handle and multiple maintainers, and ensure
commit message explains the replacement so review routing and ownership of
dependency/CI/telemetry changes works correctly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 51485284-735f-4dcd-9dd9-ee492b3cb4de

📥 Commits

Reviewing files that changed from the base of the PR and between 96d266b and 166d9bf.

📒 Files selected for processing (4)
  • .github/CODEOWNERS
  • CHANGELOG.md
  • src/pythinker_code/soul/permission.py
  • tests/core/test_permission_profiles.py

…bypass

- CODEOWNERS: @mohamed-elkholy95 is a renamed/invalid login (404 on GitHub);
  use the current maintainer account @elkaix so code-owner review routing works.
- permission.py: `git -c key=val <subcmd>` evaded git-network detection because
  _git_subcommand returned the -c value as the subcommand; consume -c and
  --config-env values so fetch/clone/ls-remote stay blocked in read-only profiles.
- docs: align the Agent tool description's stale 'three built-in subagents' line
  with the full built-in subagent table.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/CODEOWNERS:
- Around line 11-30: Replace the single-user handle "`@elkaix`" in
.github/CODEOWNERS with a GitHub team that actually has repo access (e.g.,
"`@Pythoughts-labs/reviewers`") so review routing works; update every occurrence
(the top-level "*", dependency entries like "pyproject.toml",
"package.json"/"package-lock.json" and their globs, telemetry path
"src/pythinker_code/telemetry/", docs "docs/en/reference/telemetry.md", CI
workflows ".github/workflows/" and the CODEOWNERS file itself) to reference the
team instead of "`@elkaix`" ensuring the chosen team exists and has the required
permissions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: bf1f3201-5993-4aa0-bbde-24e56983485d

📥 Commits

Reviewing files that changed from the base of the PR and between 166d9bf and 1fe3dab.

📒 Files selected for processing (4)
  • .github/CODEOWNERS
  • docs/en/customization/agents.md
  • src/pythinker_code/soul/permission.py
  • tests/core/test_permission_profiles.py

Comment thread .github/CODEOWNERS
Stripping -c/--config-env (previous commit) was insufficient: `git -c
core.pager=<cmd> log` runs arbitrary commands via an otherwise read-only
subcommand, and stripping the value hid the override behind an allowed
subcommand.

Instead, treat any -c/--config-env/--exec-path on a git command as unsafe in
read-only/review/verify profiles and block it outright (judge/verifier never
need config overrides). Plain read-only git (diff/log/show/status, -C <path>)
stays allowed. Flagged by automated security review.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
tests/core/test_permission_profiles.py (1)

77-79: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Keep this denial test fully offline.

If the guard regresses, this command will make a real outbound request in CI. A no-network invocation of a blocked client, such as curl --version, still exercises the same permission path without depending on external connectivity.

Suggested change
-        result = await shell(ShellParams(command="curl -s https://example.com"))
+        result = await shell(ShellParams(command="curl --version"))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/core/test_permission_profiles.py` around lines 77 - 79, The test
currently invokes Shell with ShellParams(command="curl -s https://example.com")
which performs a real outbound request; change the command to a no-network
invocation that still exercises the denial path (e.g. ShellParams(command="curl
--version") or another local-only curl flag) so the test remains fully offline;
update the call in the with tool_call_context("Shell") block where
Shell(Approval(yolo=True), environment, runtime) is instantiated and the
resulting await shell(...) invocation uses the offline command.
src/pythinker_code/soul/permission.py (1)

360-364: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Fail-closed git subcommand handling in _segment_mutation_reason (blocks unknowns + git <alias> with !)

        subcommand = _git_subcommand(args)
        if subcommand in _GIT_MUTATIONS:
            return f"git {subcommand}"
        if subcommand in _GIT_NETWORK:
            return f"network access via git {subcommand}"

In src/pythinker_code/soul/permission.py (_segment_mutation_reason), if base == "git" and _has_unsafe_git_global_option(args) is false, only _GIT_MUTATIONS / _GIT_NETWORK are blocked; any other git <subcommand> is allowed (fail-open). This is a security boundary hole: Git aliases defined in gitconfig like alias.foo =! <shell command> are executed as shell commands when invoked as git foo, even though foo is not a built-in. Deny/allowlist unknown git subcommands here (fail closed for read-only/review/verify), not just the small set that are known mutating/networking.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pythinker_code/soul/permission.py` around lines 360 - 364, In
_segment_mutation_reason, when base == "git" and
_has_unsafe_git_global_option(args) is false, don't allow unknown git
subcommands by default; after computing subcommand via _git_subcommand(args),
keep the existing checks for _GIT_MUTATIONS and _GIT_NETWORK, and add a fallback
that treats any subcommand not in the known safe/read-only allowlist as a
mutation (i.e., return f"git {subcommand}" or otherwise mark it denied) so git
aliases like `git foo` (which may run shell commands via `alias.foo =! ...`) are
blocked—update the logic around _git_subcommand, _GIT_MUTATIONS and _GIT_NETWORK
in _segment_mutation_reason to fail-closed for unknown subcommands.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/pythinker_code/soul/permission.py`:
- Around line 360-364: In _segment_mutation_reason, when base == "git" and
_has_unsafe_git_global_option(args) is false, don't allow unknown git
subcommands by default; after computing subcommand via _git_subcommand(args),
keep the existing checks for _GIT_MUTATIONS and _GIT_NETWORK, and add a fallback
that treats any subcommand not in the known safe/read-only allowlist as a
mutation (i.e., return f"git {subcommand}" or otherwise mark it denied) so git
aliases like `git foo` (which may run shell commands via `alias.foo =! ...`) are
blocked—update the logic around _git_subcommand, _GIT_MUTATIONS and _GIT_NETWORK
in _segment_mutation_reason to fail-closed for unknown subcommands.

In `@tests/core/test_permission_profiles.py`:
- Around line 77-79: The test currently invokes Shell with
ShellParams(command="curl -s https://example.com") which performs a real
outbound request; change the command to a no-network invocation that still
exercises the denial path (e.g. ShellParams(command="curl --version") or another
local-only curl flag) so the test remains fully offline; update the call in the
with tool_call_context("Shell") block where Shell(Approval(yolo=True),
environment, runtime) is instantiated and the resulting await shell(...)
invocation uses the offline command.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d5511dab-d0df-49c6-948a-452e07076746

📥 Commits

Reviewing files that changed from the base of the PR and between 1fe3dab and 8ed5a9e.

📒 Files selected for processing (2)
  • src/pythinker_code/soul/permission.py
  • tests/core/test_permission_profiles.py

@elkaix elkaix merged commit b9c85db into main Jun 1, 2026
27 checks passed
@elkaix elkaix deleted the release/0.28.0 branch June 1, 2026 13:10
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.

1 participant