Lab: find out what your policy actually matches
Write three patterns you believe are narrow, then list what each one really reaches.
The policy lesson gave you 1Claw's glob semantics: a single asterisk matches one segment and a double asterisk matches any depth. That is correct for 1Claw and it is not universal, and the gap between the semantics you assume and the ones your engine implements is where scope quietly widens.
This lab uses Python's fnmatch, which is what a naive implementation reaches for. Watch what it does with patterns that look obviously narrow.
- 1
List the paths in a vault, then ask three patterns what they reach.
bashcat > /tmp/glob.py <<'EOF' import fnmatch PATHS = ["app/key", "app/billing/stripe", "app/billing/eu/vat", "apps/other/key", "app-staging/key"] # how a naive implementation often handles ** : collapse it to * naive = lambda pat, path: fnmatch.fnmatch(path, pat.replace("**", "*")) print("intent: everything directly under app/, and NOT the billing subtree\n") for pat in ["app/*", "app/**", "app*"]: hits = [p for p in PATHS if naive(pat, p)] print(f" {pat:10} -> {hits}") EOF python3 /tmp/glob.py - 2
Three patterns, three surprises.
textintent: everything directly under app/, and NOT the billing subtree app/* -> ['app/key', 'app/billing/stripe', 'app/billing/eu/vat'] app/** -> ['app/key', 'app/billing/stripe', 'app/billing/eu/vat'] app* -> ['app/key', 'app/billing/stripe', 'app/billing/eu/vat', 'apps/other/key', 'app-staging/key'] - 3
Clean up.
bashrm /tmp/glob.py
- app/* reached two levels down, because fnmatch's asterisk crosses the separator. If you assumed shell behaviour, where an asterisk stops at a slash, you just granted the billing subtree.
- app/** behaved identically, so under this implementation the two patterns you would use to mean different things mean the same thing.
- app* reached apps/other/key and app-staging/key. A single missing slash walked out of the prefix entirely and into two sibling trees you did not know existed.
None of this contradicts what the policies lesson told you about 1Claw, where a single asterisk does stop at one segment. That is the point: the same pattern means different things in different engines, and a pattern you carry over from another system will not necessarily mean what it meant there.
The habit worth forming is small. Before relying on a pattern, list what it matches against the paths you actually have, including the ones you did not intend to include. A grant is defined by what it reaches, not by what you meant.
The third case is the one to watch for in review. Prefixes without a trailing separator are how a policy meant for app/ ends up covering app-staging/, and it reads as narrow at a glance because it is short.
Check your understanding
3 questionsUnder fnmatch, why did app/* reach app/billing/stripe?
What went wrong with app* specifically?
What does this lab imply about 1Claw's documented semantics?