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
3 changes: 2 additions & 1 deletion lib/repair-opencode-json.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,8 @@ def expected_edit_permission(
logs = list(log_paths or [])

source_keys = [f"{path}/**" for path in sources]
log_keys = [f"{path}/**" for path in logs]
# A log path may be a directory or a single file; emit both forms.
log_keys = [k for path in logs for k in (path, f"{path}/**")]
managed_keys = set(MANAGED_ROOTS) | set(source_keys) | set(writable) | set(log_keys)

permission = data.get("permission", {})
Expand Down
8 changes: 6 additions & 2 deletions runtimes/opencode.sh
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,11 @@ runtime_generate_config() {
if [ -n "$_ext_rules" ]; then
_ext_rules="${_ext_rules},"
fi
_ext_rules="${_ext_rules}\n \"${_log_path}/**\": \"allow\""
# Both patterns, because a log path may be a directory (/var/log/nginx) or
# a single file (/var/log/php8.4-fpm.log). Appending /** alone silently
# matches nothing for the file case, which is a grant that looks present
# and does nothing.
_ext_rules="${_ext_rules}\n \"${_log_path}\": \"allow\",\n \"${_log_path}/**\": \"allow\""
done < <(source_policy_log_paths)

if [ -n "$_ext_rules" ]; then
Expand Down Expand Up @@ -333,7 +337,7 @@ runtime_generate_config() {
if [ -n "$_edit_rules" ]; then
_edit_rules="${_edit_rules},"
fi
_edit_rules="${_edit_rules}\n \"${_log_path}/**\": \"deny\""
_edit_rules="${_edit_rules}\n \"${_log_path}\": \"deny\",\n \"${_log_path}/**\": \"deny\""
done < <(source_policy_log_paths)
OPENCODE_JSON="$OPENCODE_JSON${_edit_rules}"
OPENCODE_JSON="$OPENCODE_JSON\n }"
Expand Down
10 changes: 8 additions & 2 deletions tests/posture.sh
Original file line number Diff line number Diff line change
Expand Up @@ -248,15 +248,21 @@ import json,sys
k=list(json.load(open(sys.argv[1]))["permission"]["edit"])
print(k.index("wp-content/themes/**") < k.index("wp-content/themes/acme/**"))' "$MGD_JSON")" \
"True" "managed emits the broad deny before the narrower allow"
assert_contains "$MGD_EDIT_JSON" '"/var/log/site": "deny"' \
"a readable log path is denied for editing as a literal"
assert_contains "$MGD_EDIT_JSON" '"/var/log/site/**": "deny"' \
"a readable log path is still denied for editing"
"a readable log path is denied for editing as a subtree"

assert_eq "$(python3 -c 'import json,sys; print("yes" if "external_directory" in json.load(open(sys.argv[1]))["permission"] else "no")' "$ENG_JSON")" \
"yes" "engineering grants the workspace directory"
MGD_EXT="$(python3 -c 'import json,sys; print(json.dumps(json.load(open(sys.argv[1]))["permission"].get("external_directory",{})))' "$MGD_JSON")"
refute_contains "$MGD_EXT" 'workspace' "managed grants no workspace directory (there is none)"
assert_contains "$MGD_EXT" '"/var/log/site/**": "allow"' \
"managed grants read on the declared log path, so the agent can debug a fatal"
"managed grants read on the declared log directory"
# A log path may be a single FILE (/var/log/php-fpm.log). Appending /** alone
# matches nothing there — a grant that looks present and does nothing.
assert_contains "$MGD_EXT" '"/var/log/site": "allow"' \
"the literal log path is granted too, so a file path actually works"

# ===========================================================================
echo "==> claude-code denies every installed root (managed is refused upstream)"
Expand Down
Loading