opsec - #1535
Conversation
|
You do not have enough credits to review this pull request. Please purchase more credits to continue. |
📝 WalkthroughSummary by CodeRabbit
WalkthroughThe PR adds a new GitHub-CLI-blocking hook and test coverage, swaps and renames an existing git-push hook, updates Claude and Codex PreToolUse hook configurations to run the new scripts, and enables firewall/auditing changes on the Matic host. Changes
Sequence Diagram(s)sequenceDiagram
participant Claude
participant HookRunner as PreToolUse Hooks
participant BlockGH as block-gh-settings.sh
participant BlockPush as block-git-push.sh
participant Tool as gh (GitHub CLI)
Claude->>HookRunner: invoke PreToolUse (Bash)
HookRunner->>BlockPush: run block-git-push.sh
BlockPush-->>HookRunner: exit 0|2
HookRunner->>BlockGH: run block-gh-settings.sh
BlockGH-->>HookRunner: exit 0 (allow) or 2 (BLOCKED)
HookRunner->>Tool: proceed only if hooks exit 0
Tool-->>Claude: command executed or blocked
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Mesa DescriptionTL;DRAdds a hook to block What changed?
Description generated by Mesa. Update settings |
There was a problem hiding this comment.
Code Review
This pull request introduces a security hook to block destructive GitHub CLI commands and API mutations, accompanied by a new test suite. Additionally, it updates the NixOS configuration for the 'matic' host to include WiFi MAC randomization, firewall settings, and audit logging. Review feedback suggested hardening the command-blocking regex to prevent bypasses and simplifying subcommand extraction in the shell script.
| if echo "$command" | grep -qE '\-X\s+(PATCH|DELETE|PUT)' && echo "$command" | grep -qE '/repos/'; then | ||
| method=$(echo "$command" | grep -oE '\-X\s+(PATCH|DELETE|PUT)' | awk '{print $2}') |
There was a problem hiding this comment.
The gh api block logic is susceptible to bypasses. It currently only checks for the -X flag with a mandatory space, missing --method, --method=, and -X without a space (e.g., -XPATCH). The regex should be updated to handle these variations to ensure the security hook is effective.
| if echo "$command" | grep -qE '\-X\s+(PATCH|DELETE|PUT)' && echo "$command" | grep -qE '/repos/'; then | |
| method=$(echo "$command" | grep -oE '\-X\s+(PATCH|DELETE|PUT)' | awk '{print $2}') | |
| if echo "$command" | grep -qE '(\s-X\s*|\s--method[=\s]+)(PATCH|DELETE|PUT)\b' && echo "$command" | grep -qE '/repos/'; then | |
| method=$(echo "$command" | grep -oE '\b(PATCH|DELETE|PUT)\b' | head -n1) |
|
|
||
| # Block: gh repo <destructive-subcommand> | ||
| if echo "$command" | grep -qE 'gh\s+repo\s+(delete|rename|archive|transfer|edit)\b'; then | ||
| subcommand=$(echo "$command" | grep -oE 'gh\s+repo\s+(delete|rename|archive|transfer|edit)' | awk '{print $3}') |
There was a problem hiding this comment.
The extraction of the subcommand can be simplified. Using head -n1 ensures that only the first match is captured if multiple keywords appear in the string (e.g., in comments), and it avoids the overhead of spawning awk.
| subcommand=$(echo "$command" | grep -oE 'gh\s+repo\s+(delete|rename|archive|transfer|edit)' | awk '{print $3}') | |
| subcommand=$(echo "$command" | grep -oE '\b(delete|rename|archive|transfer|edit)\b' | head -n1) |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
config/shared/hooks/block-gh-settings.sh (1)
11-12: Minor: jq stderr is swallowed; emptycommandkey passes through as allowed.
2>/dev/nullonjqhides malformed-JSON failures (the script then treatscommandas empty and exits 0, i.e., allows the tool call). That is consistent with the{}/ empty-string tests, but note it also means a malformed payload from a future caller silently bypasses the guard. If that matters, considerexit 0only whenjqsucceeds with empty output, and fail-closed otherwise. Non-blocking.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@config/shared/hooks/block-gh-settings.sh` around lines 11 - 12, The current extraction command uses `command=$(echo "$input" | jq -r '.tool_input.command // .command // empty' 2>/dev/null)` which swallows jq errors and treats malformed JSON as an empty command (allowing the call); change this so you run jq without redirecting stderr, capture its exit status, and only call `exit 0` when jq succeeded and produced an empty string—if jq fails (non-zero exit) return a non-zero exit (fail-closed). Concretely: run the same jq expression on `$input`, check `$?` (or capture jq output+status), and if status != 0 then exit 1 (or log+exit 1); if status == 0 and the extracted `command` is empty then exit 0; otherwise proceed. This affects the `command` assignment and the `[[ -z $command ]] && exit 0` logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@config/shared/hooks/block-gh-settings.sh`:
- Around line 22-30: The current gh api mutation detection only matches "-X" and
a leading "/repos/", so update the two grep checks and the method extraction to
also handle the long form "--method" (with either space or "=" delimiter) and
repo paths without a leading slash. Specifically, replace the grep that detects
'-X' with one that matches '(-X|--method)(=|[[:space:]]+)(PATCH|DELETE|PUT)' and
replace the '/repos/' check with a pattern that allows an optional leading slash
like '(/?repos/)'; update the method assignment (the method= line) to extract
the HTTP verb from the combined '-X|--method' match (e.g., capture the
PATCH|DELETE|PUT token from the matched string) so the msg and detection remain
correct.
In `@named-hosts/matic/default.nix`:
- Around line 92-100: The priv_esc audit rule in the rules array only applies to
"arch=b64" so 32-bit setuid/setgid syscalls can bypass it; add a matching "-a
exit,always -F arch=b32 -S setuid,setgid,setresuid,setresgid -k priv_esc" entry
alongside the existing b64 priv_esc rule (keeping the existing duplicated execve
b64/b32 entries unchanged), and while editing consider verifying or configuring
auditd log rotation/size to avoid excessive AUDIT_EXECVE noise.
- Around line 80-86: The firewall config references a non-existent interface and
may enforce unintended default-deny behavior; either remove the dead rule or
enable Tailscale: either delete or comment out the "trustedInterfaces = [
\"tailscale0\" ]" entry in the networking.firewall block (and consider removing
empty allowedTCPPorts/allowedUDPPorts or adding needed service ports) OR enable
Tailscale by adding modules.tailscale with installSystemService = true (so the
tailscale0 interface is created), and keep logRefusedConnections true only if
you want denials logged. Ensure you update the networking.firewall block and/or
add modules.tailscale so the configuration is consistent.
---
Nitpick comments:
In `@config/shared/hooks/block-gh-settings.sh`:
- Around line 11-12: The current extraction command uses `command=$(echo
"$input" | jq -r '.tool_input.command // .command // empty' 2>/dev/null)` which
swallows jq errors and treats malformed JSON as an empty command (allowing the
call); change this so you run jq without redirecting stderr, capture its exit
status, and only call `exit 0` when jq succeeded and produced an empty string—if
jq fails (non-zero exit) return a non-zero exit (fail-closed). Concretely: run
the same jq expression on `$input`, check `$?` (or capture jq output+status),
and if status != 0 then exit 1 (or log+exit 1); if status == 0 and the extracted
`command` is empty then exit 0; otherwise proceed. This affects the `command`
assignment and the `[[ -z $command ]] && exit 0` logic.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 797c9f5f-527b-49e5-bab2-7ae38fc84028
📒 Files selected for processing (4)
config/claude/settings.jsonconfig/shared/hooks/block-gh-settings.shnamed-hosts/matic/default.nixspec/block_gh_settings_spec.sh
| # Block: gh api -X PATCH|DELETE|PUT targeting /repos/ | ||
| if echo "$command" | grep -qE 'gh\s+api'; then | ||
| if echo "$command" | grep -qE '\-X\s+(PATCH|DELETE|PUT)' && echo "$command" | grep -qE '/repos/'; then | ||
| method=$(echo "$command" | grep -oE '\-X\s+(PATCH|DELETE|PUT)' | awk '{print $2}') | ||
| msg="'gh api -X $method /repos/...' is blocked. Repo API mutations must be done manually." | ||
| echo "BLOCKED by block-gh-settings.sh: $msg" >&2 | ||
| exit 2 | ||
| fi | ||
| fi |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Does gh CLI gh apiaccept both--method DELETEand paths without leading slash likerepos/owner/repo?
💡 Result:
Yes, the gh CLI gh api command accepts both --method DELETE (or the short form -X DELETE) and paths without a leading slash like repos/owner/repo. The official documentation shows examples using -X for methods like GET and PATCH, confirming --method DELETE works similarly as it overrides the default method. A GitHub CLI maintainer example explicitly uses gh api -X DELETE repos/${username}/${reponame} for deleting a repository, demonstrating DELETE with a path starting repos/owner/repo without a leading slash. Multiple sources confirm gh api accepts paths both with and without a leading slash (e.g., /repos/... or repos/...), prepending the base API URL appropriately. Examples in the manual consistently use paths without leading slashes like repos/{owner}/{repo}/releases. While Git Bash on Windows may misinterpret leading slashes due to path expansion, this is a shell issue, not a limitation of gh CLI, and paths without leading slashes work universally.
Citations:
- 1: Delete a repo with API with use of gh. cli/cli#3456
- 2: https://cli.github.com/manual/gh_api
- 3:
gh apiexample paths should not have a leading slash github/rest-api-description#2140 - 4: gh api should allow leading / in REST endpoints cli/cli#2096
- 5:
gh apifails due to absolute path expansion in git bash cli/cli#6415
Tighten regex patterns to close bypass vectors in gh api mutation detection.
The script blocks destructive mutations via -X DELETE /repos/..., but two real bypasses exist:
--method DELETEflag works equivalently to-X DELETEper official gh CLI documentation, but the regex only matches-X- Paths work without leading slash (
repos/owner/reponot just/repos/owner/repo) per documentation and GitHub maintainer examples
Both bypasses should be closed. Update the regex patterns to match:
-Xand--methodforms (with spacing/delimiter variations:-X DELETE,--method=DELETE,--method DELETE)/repos/andrepos/path formats (with optional leading slash)
Proposed fix
# Block: gh api -X PATCH|DELETE|PUT targeting /repos/
if echo "$command" | grep -qE 'gh\s+api'; then
- if echo "$command" | grep -qE '\-X\s+(PATCH|DELETE|PUT)' && echo "$command" | grep -qE '/repos/'; then
- method=$(echo "$command" | grep -oE '\-X\s+(PATCH|DELETE|PUT)' | awk '{print $2}')
+ if echo "$command" | grep -qE '(-X|--method)[= ]+(PATCH|DELETE|PUT)\b' \
+ && echo "$command" | grep -qE '(^|[[:space:]=])/?repos/'; then
+ method=$(echo "$command" | grep -oE '(-X|--method)[= ]+(PATCH|DELETE|PUT)' | grep -oE '(PATCH|DELETE|PUT)')
msg="'gh api -X $method /repos/...' is blocked. Repo API mutations must be done manually."
echo "BLOCKED by block-gh-settings.sh: $msg" >&2
exit 2
fi
fiAdd test cases in spec/block_gh_settings_spec.sh:
It 'blocks gh api --method DELETE /repos/...'
Data '{"tool_input": {"command": "gh api --method DELETE /repos/owner/repo"}}'
When run bash "$SCRIPT"
The status should eq 2
The stderr should include 'BLOCKED'
End
It 'blocks gh api -X DELETE repos/... (no leading slash)'
Data '{"tool_input": {"command": "gh api -X DELETE repos/owner/repo"}}'
When run bash "$SCRIPT"
The status should eq 2
The stderr should include 'BLOCKED'
End🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@config/shared/hooks/block-gh-settings.sh` around lines 22 - 30, The current
gh api mutation detection only matches "-X" and a leading "/repos/", so update
the two grep checks and the method extraction to also handle the long form
"--method" (with either space or "=" delimiter) and repo paths without a leading
slash. Specifically, replace the grep that detects '-X' with one that matches
'(-X|--method)(=|[[:space:]]+)(PATCH|DELETE|PUT)' and replace the '/repos/'
check with a pattern that allows an optional leading slash like '(/?repos/)';
update the method assignment (the method= line) to extract the HTTP verb from
the combined '-X|--method' match (e.g., capture the PATCH|DELETE|PUT token from
the matched string) so the msg and detection remain correct.
| networking.firewall = { | ||
| enable = true; | ||
| trustedInterfaces = [ "tailscale0" ]; | ||
| allowedTCPPorts = [ ]; | ||
| allowedUDPPorts = [ ]; | ||
| logRefusedConnections = true; | ||
| }; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Confirm whether tailscale is actually enabled on the matic host (directly or transitively).
rg -nP -C2 '\b(services\.tailscale|modules\.tailscale)\b' named-hosts/matic/ hosts/ modules/ 2>/dev/null
echo '---'
# Also check if any imported module pulls in tailscale for matic.
fd -t f . named-hosts/matic hosts | xargs rg -nP '\btailscale\b' 2>/dev/nullRepository: shunkakinoki/dotfiles
Length of output: 70
Remove dead firewall config or enable Tailscale on this host.
trustedInterfaces = [ "tailscale0" ] references an interface that isn't enabled anywhere in matic's configuration (unlike named-hosts/kyber/default.nix, which enables modules.tailscale with installSystemService = true). If tailscale0 never comes up, this is dead firewall config.
Combined with allowedTCPPorts = [ ] and allowedUDPPorts = [ ], the default-deny stance may also block local service discovery you rely on (mDNS/Avahi for printers, CUPS, KDEConnect/GSConnect, Steam in-home streaming, Spotify Connect, etc.). The logRefusedConnections = true setting will surface these denials in the journal, but that's reactive rather than preventive. Either enable Tailscale on this host or remove the tailscale0 trust rule.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@named-hosts/matic/default.nix` around lines 80 - 86, The firewall config
references a non-existent interface and may enforce unintended default-deny
behavior; either remove the dead rule or enable Tailscale: either delete or
comment out the "trustedInterfaces = [ \"tailscale0\" ]" entry in the
networking.firewall block (and consider removing empty
allowedTCPPorts/allowedUDPPorts or adding needed service ports) OR enable
Tailscale by adding modules.tailscale with installSystemService = true (so the
tailscale0 interface is created), and keep logRefusedConnections true only if
you want denials logged. Ensure you update the networking.firewall block and/or
add modules.tailscale so the configuration is consistent.
| rules = [ | ||
| "-a exit,always -F arch=b64 -S execve -k exec" | ||
| "-a exit,always -F arch=b32 -S execve -k exec" | ||
| "-a exit,always -F arch=b64 -S setuid,setgid,setresuid,setresgid -k priv_esc" | ||
| "-w /etc/sudoers -p wa -k sudoers" | ||
| "-w /etc/passwd -p wa -k identity" | ||
| "-w /etc/shadow -p wa -k identity" | ||
| "-w /etc/ssh -p wa -k ssh" | ||
| ]; |
There was a problem hiding this comment.
setuid/setgid audit rule only covers arch=b64 — 32-bit binaries bypass it.
The execve rule is correctly duplicated for both b64 and b32, but the privilege-escalation rule is only installed for b64. On x86_64, any 32-bit setuid/setgid syscall (e.g. invoked by a multilib binary from Steam, Wine, or a compiled-in-32-bit tool) will silently evade the priv_esc key. Add the matching b32 rule for parity with the execve coverage.
Also consider whether unconditional execve auditing is desired here: on a desktop running Hyprland + Steam + Docker this will emit a very high volume of AUDIT_EXECVE records and, without auditd log rotation tuned, can fill /var/log/audit quickly. At minimum verify security.auditd defaults or add an explicit rotation/size cap.
🔒 Proposed fix: add b32 priv-esc rule
rules = [
"-a exit,always -F arch=b64 -S execve -k exec"
"-a exit,always -F arch=b32 -S execve -k exec"
"-a exit,always -F arch=b64 -S setuid,setgid,setresuid,setresgid -k priv_esc"
+ "-a exit,always -F arch=b32 -S setuid,setgid,setresuid,setresgid -k priv_esc"
"-w /etc/sudoers -p wa -k sudoers"
"-w /etc/passwd -p wa -k identity"
"-w /etc/shadow -p wa -k identity"
"-w /etc/ssh -p wa -k ssh"
];🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@named-hosts/matic/default.nix` around lines 92 - 100, The priv_esc audit rule
in the rules array only applies to "arch=b64" so 32-bit setuid/setgid syscalls
can bypass it; add a matching "-a exit,always -F arch=b32 -S
setuid,setgid,setresuid,setresgid -k priv_esc" entry alongside the existing b64
priv_esc rule (keeping the existing duplicated execve b64/b32 entries
unchanged), and while editing consider verifying or configuring auditd log
rotation/size to avoid excessive AUDIT_EXECVE noise.
There was a problem hiding this comment.
2 issues found across 4 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="named-hosts/matic/default.nix">
<violation number="1" location="named-hosts/matic/default.nix:95">
P2: Missing `b32` counterpart for the privilege escalation audit rule. The `execve` rules above correctly cover both `arch=b64` and `arch=b32`, but this `setuid`/`setgid` rule only monitors 64-bit syscalls. Any 32-bit setuid/setgid binary (e.g., from multilib, Wine, or Steam) will silently evade this audit rule. Add a matching `b32` rule for completeness.</violation>
</file>
<file name="config/shared/hooks/block-gh-settings.sh">
<violation number="1" location="config/shared/hooks/block-gh-settings.sh:24">
P1: The mutation filter is bypassable because it only detects `-X ...` and `/repos/` with a leading slash. `gh api --method PATCH repos/...` will not be blocked.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
|
|
||
| # Block: gh api -X PATCH|DELETE|PUT targeting /repos/ | ||
| if echo "$command" | grep -qE 'gh\s+api'; then | ||
| if echo "$command" | grep -qE '\-X\s+(PATCH|DELETE|PUT)' && echo "$command" | grep -qE '/repos/'; then |
There was a problem hiding this comment.
P1: The mutation filter is bypassable because it only detects -X ... and /repos/ with a leading slash. gh api --method PATCH repos/... will not be blocked.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At config/shared/hooks/block-gh-settings.sh, line 24:
<comment>The mutation filter is bypassable because it only detects `-X ...` and `/repos/` with a leading slash. `gh api --method PATCH repos/...` will not be blocked.</comment>
<file context>
@@ -0,0 +1,32 @@
+
+# Block: gh api -X PATCH|DELETE|PUT targeting /repos/
+if echo "$command" | grep -qE 'gh\s+api'; then
+ if echo "$command" | grep -qE '\-X\s+(PATCH|DELETE|PUT)' && echo "$command" | grep -qE '/repos/'; then
+ method=$(echo "$command" | grep -oE '\-X\s+(PATCH|DELETE|PUT)' | awk '{print $2}')
+ msg="'gh api -X $method /repos/...' is blocked. Repo API mutations must be done manually."
</file context>
| rules = [ | ||
| "-a exit,always -F arch=b64 -S execve -k exec" | ||
| "-a exit,always -F arch=b32 -S execve -k exec" | ||
| "-a exit,always -F arch=b64 -S setuid,setgid,setresuid,setresgid -k priv_esc" |
There was a problem hiding this comment.
P2: Missing b32 counterpart for the privilege escalation audit rule. The execve rules above correctly cover both arch=b64 and arch=b32, but this setuid/setgid rule only monitors 64-bit syscalls. Any 32-bit setuid/setgid binary (e.g., from multilib, Wine, or Steam) will silently evade this audit rule. Add a matching b32 rule for completeness.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At named-hosts/matic/default.nix, line 95:
<comment>Missing `b32` counterpart for the privilege escalation audit rule. The `execve` rules above correctly cover both `arch=b64` and `arch=b32`, but this `setuid`/`setgid` rule only monitors 64-bit syscalls. Any 32-bit setuid/setgid binary (e.g., from multilib, Wine, or Steam) will silently evade this audit rule. Add a matching `b32` rule for completeness.</comment>
<file context>
@@ -71,7 +71,34 @@ import ../../hosts/nixos {
+ rules = [
+ "-a exit,always -F arch=b64 -S execve -k exec"
+ "-a exit,always -F arch=b32 -S execve -k exec"
+ "-a exit,always -F arch=b64 -S setuid,setgid,setresuid,setresgid -k priv_esc"
+ "-w /etc/sudoers -p wa -k sudoers"
+ "-w /etc/passwd -p wa -k identity"
</file context>
| "-a exit,always -F arch=b64 -S setuid,setgid,setresuid,setresgid -k priv_esc" | |
| "-a exit,always -F arch=b64 -S setuid,setgid,setresuid,setresgid -k priv_esc" | |
| "-a exit,always -F arch=b32 -S setuid,setgid,setresuid,setresgid -k priv_esc" |
|
Only repository collaborators, contributors, or members can run CodeRabbit commands. |
- Listed the new shared hook so coverage checks expect its matching spec.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
spec/coverage_spec.sh (1)
359-360: LGTM — coverage list correctly updated.The added
block-gh-settings.shandblock-git-push.shentries align with the hook renames/additions elsewhere in this PR, and the removal ofblock-push-main.shkeeps thediff-based mismatch check in sync withgit ls-files.Optional nit: for consistency with the upper
Describe 'all required scripts have spec files'block (lines 8–305), consider adding explicitIt 'has spec file for config/shared/hooks/block-gh-settings.sh'/block-git-push.shassertions pointing atspec/block_gh_settings_spec.shandspec/block_git_push_spec.sh. Not required — the bottom diff test already enforces presence in the allowlist — but it keeps the two sections symmetric.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@spec/coverage_spec.sh` around lines 359 - 360, Add two explicit example assertions to the existing Describe 'all required scripts have spec files' block to mirror the top section: create It 'has spec file for config/shared/hooks/block-gh-settings.sh' that checks for spec/block_gh_settings_spec.sh and It 'has spec file for config/shared/hooks/block-git-push.sh' that checks for spec/block_git_push_spec.sh; this keeps the block symmetric with the upper section while the bottom diff test still enforces the allowlist.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@spec/coverage_spec.sh`:
- Around line 359-360: Add two explicit example assertions to the existing
Describe 'all required scripts have spec files' block to mirror the top section:
create It 'has spec file for config/shared/hooks/block-gh-settings.sh' that
checks for spec/block_gh_settings_spec.sh and It 'has spec file for
config/shared/hooks/block-git-push.sh' that checks for
spec/block_git_push_spec.sh; this keeps the block symmetric with the upper
section while the bottom diff test still enforces the allowlist.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 0020f335-a0d4-400b-9bb9-ed1b830d30ec
📒 Files selected for processing (5)
config/claude/settings.jsonconfig/codex/hooks.jsonconfig/shared/hooks/block-git-push.shspec/block_git_push_spec.shspec/coverage_spec.sh
✅ Files skipped from review due to trivial changes (3)
- spec/block_git_push_spec.sh
- config/shared/hooks/block-git-push.sh
- config/codex/hooks.json
🚧 Files skipped from review as they are similar to previous changes (1)
- config/claude/settings.json
Summary by cubic
Adds a hook to block
ghcommands that modify repo settings and hardens thematichost’s network and audit config. This prevents accidental repo mutations and improves system visibility.block-gh-settings.shand wired it intoconfig/claude/settings.json: blocksgh repo delete|rename|archive|transfer|editandgh api -X PATCH|DELETE|PUT /repos/...; includes ShellSpec tests and is listed inspec/coverage_spec.sh. Renamedblock-push-main.shtoblock-git-push.shand updated references inconfig/claude/settings.json,config/codex/hooks.json, and tests.named-hosts/matic/default.nix: enabled firewall with trustedtailscale0and refused-connection logs, Wi‑Fi scan MAC randomization and stable-SSID MAC, andauditdrules for exec, priv‑esc, identity files, and SSH.Written for commit 06f2ee2. Summary will update on new commits.