Protected files in the aredel repo: the real list

Contents
What this list covers
OpenCode
Claude Code
How it was checked
Open gaps and fixes

What this list covers

Every file in the aredel repo, and outside it, that a deny or ask rule protects: first in OpenCode, then the same files in Claude Code. For each file: what it holds, which rule protects it, what the rule stops and what it does not. State on 2026-10-22: the production logs have moved out of the repo (the final fix), and OpenCode runs option B, which lets the shell run and asks for risky steps. The rules live in opencode.jsonc, .opencode/agents/reviewer.md and .claude/settings.json. Why the rules look like this is explained in Deny rules for OpenCode and Claude Code.

The list was built from the rules, not by hand: every file whose path matches a pattern. *.env and *creds* were searched over the whole repo, each matching exactly one file; the folder rules cover everything inside the folder. Files that only look similar are not protected: container/tools/deploy/site.env.example ends in .example, not .env. The rules for the old log folder, container/tools/analyze_logs/site_logs/, stay in both tools, so a copy that lands there again is still covered.

The visitor-records folder was left off this list at first: on 2026-10-22 the live site still served two of its files to anyone. Since the same day the site answers 404 for the whole folder, through RedirectMatch 404 ^/services/user_profile/data/ in the root .htaccess, so it is listed like the others.

OpenCode

Rules in opencode.jsonc apply to every role. On top of them, triage denies grep, all edits and shell; reviewer denies all edits, allows only read-only git in the shell and repeats the shell denies after those allows; build and builder add nothing. Under option B the shell runs without a prompt, so for every file below a shell rule, not your approval, decides whether a command that names it runs.

FileWhat it holdsRuleProtected fromStill not protected against
~/.local/share/aredel/logs/: every file, among them the access logs in prod/access/ and the error logs in prod/error/ (aredel.com.access.log, aredel.com.error.log and their daily copies *.log.YYYYMMDD), and the devices/ and user_profiles/ folders the profile tools fillproduction logs and copies of the visitor records from dev: IP addresses, user agents, URLs, device idsexternal_directory ~/.local/share/aredel/logs/* ask, read */.local/share/aredel/logs/* ask, edit */.local/share/aredel/logs/* deny, shell *aredel/logs* ask, shell *analyze_logs* ask; in the reviewer file shell *aredel/logs* denyread, grep and glob tools without a prompt (test 10, option B); shell commands that name the folder, and every tool in analyze_logs, which find the folder themselves: they ask (option B); git diff --no-index through a role allow: builder asks, reviewer is denied (check 9); edit and write for every roleeverything under --auto, which approves the ask rules (test 10); shell commands and scripts that reach the folder without naming it, such as find ~ -name "*.log" -exec cat {} +; a file you attach with @ or -f (test 6)
container/src/services/user_profile/data/: visitors.jsonl, password_profiles.jsonl (listed since 2026-10-22)visitor records written by /services/user_profile/: IPs, request headers, device idsread *services/user_profile/data/* deny, edit *services/user_profile/data/* deny, shell *user_profile/data* deny, repeated in the reviewer fileread tool for every role (test 2, test 9); shell commands that name the path, for every role, and grep -r, which asks (option B); grep tool for triage, which has no grep (test 7); edit and write for every role (check 1)grep tool for build, builder and reviewer (test 3); file names through glob (test 4); commands and scripts that reach the folder without naming it, such as find . -exec cat {} +; a file you attach with @ or -f (test 6)
container/tools/analyze_logs/users.dbevery device the visitor records saw: device ids, IPs, user agentsread *analyze_logs/users.db deny, edit *analyze_logs/users.db deny, shell *users.db* deny, repeated in the reviewer fileread tool and shell commands that name it, for every role (check 10); grep tool for triage, which has no grep (test 7); edit and write for every rolegrep tool for build, builder and reviewer (test 3); scripts that open it without naming it; a file you attach with @ or -f (test 6)
container/tools/deploy/site.envtracked, non-secret deploy settings: URLs, document roots, analytics idsread *.env deny, edit *.env deny, shell *.env* denyread tool for every role (test 2, test 9); shell commands that name the path, for every role (same rule shape as check 6); grep tool for triage, which has no grep (test 7); edit and write for every role (check 1)grep tool for build, builder and reviewer (test 3); file name through glob (test 4); scripts that open it without naming it; a file you attach with @ or -f (test 6)
container/tools/deploy/deploy-ftp.creds.exampletracked template for the FTP credentials, no real valuesread *creds* deny, edit *creds* deny, shell *creds* denyread tool for every role (test 2, test 9); shell commands that name the path, for every role (check 6, check 7); grep tool for triage, which has no grep (test 7); edit and write for every role (check 1)grep tool for build, builder and reviewer (test 3); file name through glob (test 4); scripts that open it without naming it; a file you attach with @ or -f (test 6)
~/.config/aredel/ftp-creds.envFTP password for the hostingread ~/.config/aredel/* deny, edit ~/.config/aredel/* deny, shell *.config/aredel* deny, and the *creds* and *.env rules aboveread tool for every role (test 2, test 9); shell commands that name the path, for every role (check 6, check 7); grep and glob tools without a prompt: the folder is outside the project, so they ask first (check 8); edit and write for every role (check 1)the grep tool once you approve its prompt, or under --auto: a read deny does not stop grep (test 3, test 10); commands and scripts that reach the file without naming it; a file you attach with @ or -f (test 6)
~/.config/aredel/backoffice/: token, deploy-state.json, tab-stats.jsonbearer token of the local backoffice API, commit of the last upload, tab usage countersread ~/.config/aredel/* deny, edit ~/.config/aredel/* deny, shell *.config/aredel* deny
~/.ssh/, ~/.gnupg/, ~/.docker/config.json, ~/.local/share/opencode/auth.json, ~/.local/share/opencode/opencode.db*SSH and GPG keys, the Docker registry login, the provider keys of OpenCode, every past OpenCode sessionread and edit deny on */.ssh/*, */.gnupg/*, */.docker/config.json, */.local/share/opencode/auth.json, */.local/share/opencode/opencode.db*; shell deny on *.ssh/*, *.gnupg*, *.docker/config.json*, *opencode/auth.json*, *opencode.db*, repeated in the reviewer fileread tool for every role, also under --auto; shell commands that name the path (check 8); grep and glob tools without a prompt (check 8); edit and write for every rolethe grep tool once you approve its prompt, or under --auto (test 3, test 10); commands and scripts that reach them without naming them; a file you attach with @ or -f

Claude Code

Rules in .claude/settings.json apply to every session and every subagent started in the repo. A Read deny also blocks Edit and Write on the same path.

FileWhat it holdsRuleProtected fromStill not protected against
~/.local/share/aredel/logs/: every file, as in the OpenCode tableproduction logs and copies of the visitor records from dev: IP addresses, user agents, URLs, device idsRead(~/.local/share/aredel/logs/**)Read tool; Edit and Write; cat, grep, ls and find that name the path; Grep and Glob tools and @ mentions. The same rule shape passed checks 2 to 4 on the old folder; not tested here, because the folder holds real logscommands that reach the folder without naming it, such as grep -r over the home folder (check 5); a grep -r inside the repo no longer reaches it; scripts such as Python that open the files themselves; copy and paste by you
container/src/services/user_profile/data/: visitors.jsonl, password_profiles.jsonl (listed since 2026-10-22)visitor records written by /services/user_profile/: IPs, request headers, device idsRead(//**/services/user_profile/data/**)Read tool (tested in the repo session); Edit and Write (check 2); cat, grep, ls and find that name the path (check 3, check 4); Grep and Glob tools and @ mentions (docs, best effort)grep -r and other commands run from a parent folder that do not name the file: grep is a read-only command and runs without a prompt (check 5); scripts such as Python that open the file themselves; copy and paste by you
container/tools/analyze_logs/users.dbevery device the visitor records saw: device ids, IPs, user agentsRead(//**/analyze_logs/users.db)Read tool; Edit and Write; cat and the other file commands Claude Code recognizes, when they name the path (docs; not tested on this path)grep -r from a parent folder (check 5); sqlite3, Python and other programs that Claude Code does not treat as file reads; copy and paste by you
container/tools/deploy/site.envtracked, non-secret deploy settings: URLs, document roots, analytics idsRead(**/*.env)Read tool (tested in the repo session); Edit and Write (check 2); cat, grep, ls and find that name the path (check 3, check 4); Grep and Glob tools and @ mentions (docs, best effort)grep -r and other commands run from a parent folder that do not name the file (check 5); scripts such as Python that open the file themselves; copy and paste by you; **/ rules match only under the folder the session starts in, so a session started in a sibling folder misses *.env and *creds* files
container/tools/deploy/deploy-ftp.creds.exampletracked template for the FTP credentials, no real valuesRead(**/*creds*)
~/.config/aredel/ftp-creds.env, and in ~/.config/aredel/backoffice/: token, deploy-state.json, tab-stats.jsonFTP password for the hosting, bearer token of the local backoffice API, commit of the last upload, tab usage countersRead(~/.config/aredel/**)Read tool (tested in the repo session); Edit and Write (check 2); cat, grep, ls and find that name the path (check 3, check 4); Grep and Glob tools and @ mentions (docs, best effort)commands that do not name the file, as for the logs (not tested on this path); scripts such as Python that open the file themselves; copy and paste by you

How it was checked

Read, grep, glob, shell and attachment results come from the tests in How to test a deny rule and the option tables there. The checks below were added for this list, on the same throwaway repo with a dummy log, so no real file was read or changed. Checks 1 to 7 ran while the logs were still in the repo, on the old path; checks 8 to 10 ran on 2026-10-22 with OpenCode 2.1.3, with a fake home folder next to the throwaway repo standing in for ~.

Check 1 — OpenCode write on a read-protected file. The default build agent has no edit rule, so the read deny is the only rule on the file.

timeout 180 opencode run --standalone -m opencode/deepseek-v4.1-flash-free "Use the write tool exactly once to replace the whole content of container/tools/analyze_logs/site_logs/prod/access/aredel.com.access.log with the single word OVERWRITTEN. Then reply with the exact result or the exact error text. Do not use any other tool."

Check 2 — Claude Code Write on a read-protected file. Asked Claude Code to overwrite the same dummy log with its Write tool.

Check 3 — Claude Code cat and grep that name the file. Shell commands with the protected path on the command line.

cat container/tools/analyze_logs/site_logs/prod/access/aredel.com.access.log

grep -c 203 container/tools/analyze_logs/site_logs/prod/access/aredel.com.access.log

Check 4 — Claude Code ls and find on a protected folder. Listing names inside a protected folder.

find container/tools/analyze_logs/site_logs -type f

Check 5 — Claude Code grep -r from the parent folder. A command that reads the file without naming it.

cd container/tools/analyze_logs && grep -rc 203 .

Check 6 — OpenCode shell commands that name the config folder or creds. The default agent, with the shell denies in opencode.jsonc. The throwaway repo has a dummy file at fakehome/.config/aredel/dummy.txt.

timeout 180 opencode run --standalone -m opencode/deepseek-v4.1-flash-free "Use the shell tool exactly once to run: cat fakehome/.config/aredel/dummy.txt . Then reply with the output or the exact error text. Do not use any other tool."

timeout 180 opencode run --standalone -m opencode/deepseek-v4.1-flash-free "Use the shell tool exactly once to run: echo creds-check . Then reply with the output or the exact error text. Do not use any other tool."

Check 7 — OpenCode agent allows after a global deny. Builder allowed git diff * at the time and reviewer git diff * and git show *. OpenCode applies the last matching rule, and agent rules come after the global ones.

timeout 180 opencode run --standalone --agent builder -m opencode/deepseek-v4.1-flash-free "Use the shell tool exactly once to run this exact command, with no extra arguments: git diff --no-index /dev/null fakehome/.config/aredel/dummy.txt Then reply with the output or the exact error text. Do not use any other tool."

Check 8 — OpenCode files outside the project. A dummy key at fakehome/.ssh/id_dummy and a dummy note at fakehome/notes.txt, outside the throwaway repo. First the config before option B, then option B.

timeout 180 opencode run --standalone -m opencode/deepseek-v4.1-flash-free "Use the read tool exactly once on /tmp/fakehome/.ssh/id_dummy. Then reply with the output, or with the exact error text the tool returned. Do not use any other tool." < /dev/null

Check 9 — OpenCode role allows on the moved logs. The dummy log in the fake home folder, with the folder ask rule already in place.

timeout 180 opencode run --standalone --agent builder -m opencode/deepseek-v4.1-flash-free "Use the shell tool exactly once to run this exact command, with no extra arguments: git diff --no-index /dev/null /tmp/fakehome/.local/share/aredel/logs/prod/access/aredel.com.access.log Then reply with the output or the exact error text. Do not use any other tool." < /dev/null

Check 10 — OpenCode on users.db. A dummy database with one row at container/tools/analyze_logs/users.db, option B.

timeout 180 opencode run --standalone -m opencode/deepseek-v4.1-flash-free "Use the read tool exactly once on container/tools/analyze_logs/users.db. Then reply with the output, or with the exact error text the tool returned. Do not use any other tool." < /dev/null

Then the same through Python in the shell: python3 -c "import sqlite3; print(sqlite3.connect(…/users.db).execute('select * from users').fetchall())".

Open gaps and fixes

Article author: Arthur Isaev

Related articles
AI
AI security: secrets and access rights
Deny rules for OpenCode and Claude Code
Protected files in the aredel repo
How an FTP password leaked to a free AI model
Add file context with @ in OpenCode and Claude Code
Agent setup audit: the aredel case

Search this site

Channel @aofeed Chat @aofeedchat

Contacts and cooperation:
I recommend our hosting beget.com
Write to info@aredel.com if you:
1. Want to write an article for our site or translate an article into your native language.
2. Want to place thematically relevant ads on the site.
3. Ads on my site pass maximum censorship. If you see an ad block unsuitable for school-age children, shocking or misleading - please contact us by e-mail
4. Found a mistake, inaccuracy, bug, etc. on the site. ... .......
5. Articles can be shared on social media by clicking a network icon: