· about 40 minutes · runs on ubuntu-26.04-claude · unrated
An unrated lab. It runs on your machine with no account and no network, and everything about it — the faults, the checks, the hints and the reference solution — is in the repository. An attempt on it is recorded on your profile and never moves a rating: only rated labs do. Rated and unrated labs.
This is the platform team's shared build machine. Three rules were agreed, and none of them holds.
The security team's policy, for every Claude Code session on the machine, whoever runs it and
however: no web fetching or searching, and nobody's ~/.ssh is read. It was installed last week as a
managed settings file. Yesterday a session fetched a URL and printed a private key.
The platform team's model: routine work in ~/platform runs on Haiku, set in the project's
settings. Sessions there run on Opus.
The conventions: ~/platform/CLAUDE.md pulls in the team's coding conventions, and the model
never follows them.
This lab runs in a container, as learner with sudo. claude here is the real Claude Code
2.1.270, talking to a scripted model on this machine; which settings load, which tools are refused
and which model is requested are Claude Code's real decisions. There is a private key in
~learner/.ssh for it to be tempted by.
What is expected, and graded:
--allowedTools "WebFetch,WebSearch,Read,Bash": no web tools, and no key reaches the model.~/platform that names no model runs on Haiku.~/platform.Change the policy's location or permissions if you must, not its rules.
This lab runs in a container — Docker or Podman, no VM — so there is no boot to survive: the checks run once, against the state you left.
| Check | Objective |
|---|---|
| 01_the_machine_policy_holds_everywhere | Enforce a machine-wide policy no project, user or flag can loosen |
| 02_the_team_model_is_used | Predict which settings level wins, and keep personal settings personal |
| 03_personal_settings_stay_out_of_git | Predict which settings level wins, and keep personal settings personal |
| 04_the_conventions_reach_the_model | Make project instructions, imports included, reach the model |
Where the lab's hints send you, level by level, as you ask for them (h, then l opens a journal section in the TUI).
4 questions on the same topic, in the lab's Theory tab. They never affect the lab's grade. Three of them, to answer here:
~/.claude/settings.json says `"model": "sonnet"`, the project's .claude/settings.json says `"model": "haiku"`, and .claude/settings.local.json says `"model": "opus"`. A session is started in the project with no --model. Which model does it request?
Opus: local project settings outrank shared project settings, which outrank user settings
For a scalar key the highest level that sets it wins: managed, then the command line, then .claude/settings.local.json, then .claude/settings.json, then ~/.claude/settings.json. Verified with Claude Code 2.1.270: opus is requested; without the local file, haiku; with --model haiku on the command line, haiku. Lists such as permissions.deny merge instead.
https://code.claude.com/docs/en/settings
A policy denying WebFetch is saved as /etc/claude-code/managed-settings.json, owned by root with mode 0600. A user runs claude -p with --allowedTools WebFetch. What happens?
WebFetch is allowed: the file cannot be read, Claude Code says the policy is not in effect, and the session runs
Claude Code runs as the user, and reads managed settings as that user. With mode 0600 it prints "Managed settings failed to load; policies from the failed source are NOT in effect" and continues without them. A managed settings file holds policy, not secrets: it must be readable by everyone it governs (0644) and writable only by root.
https://code.claude.com/docs/en/settings
A project's CLAUDE.md contains the line `@docs/conventions.md`, and the file in the repository is docs/CONVENTIONS.md, on Linux. What does the model receive?
CLAUDE.md without the conventions; the import is silently dropped
Imports resolve relative to the importing file, and Linux paths are case-sensitive; an import of a file that does not exist adds nothing and produces no warning (verified with 2.1.270). The same happens to an import written inside backticks, which is not treated as an import at all.
https://code.claude.com/docs/en/memory