Thomas Piacentini
← Workshop

Cheat sheet

Skill Permissions, Evals and Supply Chain

Original text · English

Review skill actions before they run, isolate them, gate each release by eval layer and scan bundles.

Symptoms, causes and fixes

SymptomCauseFix
deny with rule workspace-jailThe target resolves outside the rootKeep targets under workspace_root
command-review deny with approved=Truerm is in DESTRUCTIVE_EXECUTABLESApproval cannot override it. Use a narrow tool
network-allowlist deny on port 8443Port 8443 is a different originAdd that origin with its port
approval-gate on an allowlisted URLinfluenced_by_untrusted_content is trueShow the target and consequence. Get approval
secret-review denyThe payload matches SECRET_PATTERNSInject the credential into one narrow tool
Lint issue orphan-fileSKILL.md does not reference the fileReference the file or remove it
fixture_passed true, passed falseNo trusted external attestationPass --attestation and --trusted-attestation-sha256
Audit usable is falseSame content or group in both partitionsUnion by content and group before the split
Sources

review_action check order

  1. policy-change always deny with rule authority-boundary.
  2. Kind a kind outside allowed_kinds gives a kind-allowlist deny.
  3. Path read, write and delete resolve through normalize_workspace_path. An escape gives workspace-jail.
  4. Command inspect_command checks the bare name, destructive set, metacharacters and argv prefix.
  5. Network normalize_https_origin adds the effective port. The origin must be in the allowlist.
  6. Secrets a contains_secret match gives deny, or require-approval with permit_secret_use_after_approval.
  7. Approval approval_kinds and untrusted influence need approved. Else rule approval-gate.
  8. Allow rule policy-allow. The field executed stays false.
Sources

Review one action

policy = SandboxPolicy(
workspace_root=workspace,resolved with strict=True
allowed_kinds=("read", "write", "delete", "command", "network"),
command_allowlist=(("python3", "-m", "unittest"),),argv prefixes
network_allowlist=("https://docs.example.test",),origins only
)
request = ActionRequest("write", target="summary.json")write is in approval_kinds
review_action(policy, request).to_dict()["verdict"]"require-approval"
request = ActionRequest("write", target="summary.json", approved=True)
review_action(policy, request).rule"policy-allow"
normalize_https_origin("https://api.example.test")adds ":443"
Sources

Run the labs and tools

CommandWhat it does
python3 code/main.pyPrints the demo decisions. It starts no process
python3 -m unittest discover -s code/tests -vRuns the lesson tests
python3 scripts/review_action.py --policy <policy> --request <request>Returns the verdict and the rule for one request
evaluate_skill.py --fixture-demo <bundle>Fixture run. fixturePassed true, productionReady false
scanner examples/reviewable 3Scans a bundle with threshold 3. Prints JSON
cli.py <cases> --out experiment.jsonProposes rules and runs the gate. It does not promote
python3 scripts/project_test.py <project> --all --solution --strictChecks every stage of the reference solution
Sources

Run the isolation drill

docker build -f code/sandbox/Containerfile -t aiefs-skill-sandbox code/sandbox
docker run --rm --network none --read-only --cap-drop ALL \
--security-opt no-new-privileges --pids-limit 64 --memory 128m --cpus 0.5 \
--tmpfs /tmp:rw,noexec,nosuid,size=16m \
--mount type=bind,src="${PWD}/code/sandbox/input",dst=/input,readonly \
--env DEMO_VALUE=bounded aiefs-skill-sandbox

expect: /input readable, image read-only, network fails

Sources

Defaults and limits

SettingDefaultNote
allowed_kinds("read",)SandboxPolicy allows reads only
approval_kinds("write", "delete", "network")These kinds need approved
MAX_SKILL_BODY_CHARS10_000Lint issue body-size above it
MAX_COMPANION_FILE_BYTES1_000_000Lint issue file-size above it
min_precision, min_recall0.8ReleaseThresholds in the lab
min_repeat_rate0.9Lowest per-case pass rate
min_gain0.05The loop gate also needs zero regressions
Scanner threshold3A threshold of 0 is an error
Sources

Isolation boundaries

FactorRestricted subprocessContainerMicroVM
IsolatesEnvironment, cwd, timeout, outputFilesystem and process namespacesSeparate guest kernel
Does not isolateKernel, host filesystem, networkShared kernel, host mountsBad mounts, credentials, egress
Typical useReviewed local utilitiesRepository builds and testsUntrusted code, high impact
Sources

Six eval layers

Structure
lint without a model. CI blocks E_* errors and allows reviewed W_* warnings.
Routing
precision and recall over positives, clear negatives and near misses. Report raw counts.
Behavior
baseline and treatment use the same model, tools, task and budget.
Scripts
test outside model runs with empty, malformed and repeated input.
Safety
record the control: instruction only, tool policy, approval, sandbox or verification.
Portability
install into a clean destination. Validate the installed copy.
Verdicts
fixturePassed, localEvidenceReady, productionReady. passed follows productionReady.
Sources

Project pipelines

linesfindingsscoredevelopmenterrorscandidatespansUTF-8 byte offsetsprocessscanthree named rulesprocessrisk_scoreonce per rule and lineprocessreviewreview-required orbelow-thresholdclientsplit_casescontent and group unionstoreevaluateper-case rowsprocessproposedev errors, min_support 2processgategain and regressionsclient
Nodes and connections
NodeRoleKind
spansUTF-8 byte offsetsprocess
scanthree named rulesprocess
risk_scoreonce per rule and lineprocess
reviewreview-required or below-thresholdclient
split_casescontent and group unionstore
evaluateper-case rowsprocess
proposedev errors, min_support 2process
gategain and regressionsclient
FromToConnection
spansscanlines
scanrisk_scorefindings
risk_scorereviewscore
split_casesevaluatedevelopment
evaluateproposeerrors
proposegatecandidate
Sources
  • projects/skill-scanner/solution
  • projects/self-improving-skill-loop/solution

Tasks in code

TaskCode
Lint a bundlelint_package(root)
Score routingclassification_metrics(expected, predicted)
Check an installed copyverify_manifest(root, expected)
Host support matrixportability_matrix(requirements, hosts)
Split without leakagesplit_cases(cases, holdout_fraction=0.25)
Propose rulespropose(development, rules, min_support=2)
Gate a candidategate(holdout, baseline, candidate)
Refine a library skillregister(skill, dedup=True) bumps the version
Sources

Questions

Does allowed-tools sandbox a skill?
No. It affects capability or permission prompts. It is not OS isolation.
Does a hash prove a package is safe?
No. It proves that the bytes match a manifest.
Is a below-threshold scan safe?
No. Only these rules did not cross the threshold.
Why version skills?
A parent pinned to v1 does not pick up a refined v3.
Why rotate the holdout?
Repeated tuning on the same holdout leaks information.
Sources
Original source
---
id: skill-trust-evals
title: Skill Permissions, Evals and Supply Chain
code: SE
subtitle: Review skill actions before they run, isolate them, gate each release by eval layer and scan bundles.
hue: 340
sources: phases/13-tools-and-protocols/26-skill-permissions-sandboxes-and-trust, phases/13-tools-and-protocols/27-skill-evals-packaging-and-portability, phases/14-agent-engineering/10-skill-libraries-voyager, projects/skill-scanner, projects/self-improving-skill-loop
source_hash: f18344df1d141366
---

## Symptoms, causes and fixes
type: troubleshooting
from: phases/13-tools-and-protocols/26-skill-permissions-sandboxes-and-trust/docs/en.md, phases/13-tools-and-protocols/26-skill-permissions-sandboxes-and-trust/code/main.py, phases/13-tools-and-protocols/27-skill-evals-packaging-and-portability/docs/en.md, phases/13-tools-and-protocols/27-skill-evals-packaging-and-portability/code/main.py, projects/self-improving-skill-loop/README.md, projects/self-improving-skill-loop/solution/dataset.py

| Symptom | Cause | Fix |
|---|---|---|
| `deny` with rule `workspace-jail` | The target resolves outside the root | Keep targets under `workspace_root` |
| `command-review` deny with `approved=True` | `rm` is in `DESTRUCTIVE_EXECUTABLES` | Approval cannot override it. Use a narrow tool |
| `network-allowlist` deny on port 8443 | Port 8443 is a different origin | Add that origin with its port |
| `approval-gate` on an allowlisted URL | `influenced_by_untrusted_content` is true | Show the target and consequence. Get approval |
| `secret-review` deny | The payload matches `SECRET_PATTERNS` | Inject the credential into one narrow tool |
| Lint issue `orphan-file` | `SKILL.md` does not reference the file | Reference the file or remove it |
| `fixture_passed` true, `passed` false | No trusted external attestation | Pass `--attestation` and `--trusted-attestation-sha256` |
| Audit `usable` is false | Same content or group in both partitions | Union by content and group before the split |

## review_action check order
type: flow
from: phases/13-tools-and-protocols/26-skill-permissions-sandboxes-and-trust/code/main.py

1. **policy-change**: always `deny` with rule `authority-boundary`.
2. **Kind**: a kind outside `allowed_kinds` gives a `kind-allowlist` deny.
3. **Path**: read, write and delete resolve through `normalize_workspace_path`. An escape gives `workspace-jail`.
4. **Command**: `inspect_command` checks the bare name, destructive set, metacharacters and argv prefix.
5. **Network**: `normalize_https_origin` adds the effective port. The origin must be in the allowlist.
6. **Secrets**: a `contains_secret` match gives `deny`, or `require-approval` with `permit_secret_use_after_approval`.
7. **Approval**: `approval_kinds` and untrusted influence need `approved`. Else rule `approval-gate`.
8. **Allow**: rule `policy-allow`. The field `executed` stays false.

## Review one action
type: annotated-code
lang: python
from: phases/13-tools-and-protocols/26-skill-permissions-sandboxes-and-trust/code/main.py, phases/13-tools-and-protocols/26-skill-permissions-sandboxes-and-trust/docs/en.md

```python
policy = SandboxPolicy(
    workspace_root=workspace,                            # resolved with strict=True
    allowed_kinds=("read", "write", "delete", "command", "network"),
    command_allowlist=(("python3", "-m", "unittest"),),  # argv prefixes
    network_allowlist=("https://docs.example.test",),    # origins only
)
request = ActionRequest("write", target="summary.json")  # write is in approval_kinds
review_action(policy, request).to_dict()["verdict"]      # "require-approval"
request = ActionRequest("write", target="summary.json", approved=True)
review_action(policy, request).rule                      # "policy-allow"
normalize_https_origin("https://api.example.test")       # adds ":443"
```

## Run the labs and tools
type: command-table
span: 2
from: phases/13-tools-and-protocols/26-skill-permissions-sandboxes-and-trust/docs/en.md, phases/13-tools-and-protocols/26-skill-permissions-sandboxes-and-trust/outputs/skill-safety-reviewer/SKILL.md, phases/13-tools-and-protocols/27-skill-evals-packaging-and-portability/docs/en.md, projects/skill-scanner/README.md, projects/self-improving-skill-loop/README.md

| Command | What it does |
|---|---|
| `python3 code/main.py` | Prints the demo decisions. It starts no process |
| `python3 -m unittest discover -s code/tests -v` | Runs the lesson tests |
| `python3 scripts/review_action.py --policy <policy> --request <request>` | Returns the verdict and the rule for one request |
| `evaluate_skill.py --fixture-demo <bundle>` | Fixture run. `fixturePassed` true, `productionReady` false |
| `scanner examples/reviewable 3` | Scans a bundle with threshold 3. Prints JSON |
| `cli.py <cases> --out experiment.json` | Proposes rules and runs the gate. It does not promote |
| `python3 scripts/project_test.py <project> --all --solution --strict` | Checks every stage of the reference solution |

## Run the isolation drill
type: annotated-code
lang: bash
from: phases/13-tools-and-protocols/26-skill-permissions-sandboxes-and-trust/docs/en.md

```bash
docker build -f code/sandbox/Containerfile -t aiefs-skill-sandbox code/sandbox
docker run --rm --network none --read-only --cap-drop ALL \
  --security-opt no-new-privileges --pids-limit 64 --memory 128m --cpus 0.5 \
  --tmpfs /tmp:rw,noexec,nosuid,size=16m \
  --mount type=bind,src="${PWD}/code/sandbox/input",dst=/input,readonly \
  --env DEMO_VALUE=bounded aiefs-skill-sandbox
# expect: /input readable, image read-only, network fails
```

## Defaults and limits
type: defaults
from: phases/13-tools-and-protocols/26-skill-permissions-sandboxes-and-trust/code/main.py, phases/13-tools-and-protocols/27-skill-evals-packaging-and-portability/code/main.py, projects/self-improving-skill-loop/solution/promotion.py, projects/skill-scanner/solution/cli.rs

| Setting | Default | Note |
|---|---|---|
| `allowed_kinds` | `("read",)` | `SandboxPolicy` allows reads only |
| `approval_kinds` | `("write", "delete", "network")` | These kinds need `approved` |
| `MAX_SKILL_BODY_CHARS` | 10_000 | Lint issue `body-size` above it |
| `MAX_COMPANION_FILE_BYTES` | 1_000_000 | Lint issue `file-size` above it |
| `min_precision`, `min_recall` | 0.8 | `ReleaseThresholds` in the lab |
| `min_repeat_rate` | 0.9 | Lowest per-case pass rate |
| `min_gain` | 0.05 | The loop gate also needs zero regressions |
| Scanner threshold | 3 | A threshold of 0 is an error |

## Isolation boundaries
type: comparison
from: phases/13-tools-and-protocols/26-skill-permissions-sandboxes-and-trust/docs/en.md

| Factor | Restricted subprocess | Container | MicroVM |
|---|---|---|---|
| Isolates | Environment, cwd, timeout, output | Filesystem and process namespaces | Separate guest kernel |
| Does not isolate | Kernel, host filesystem, network | Shared kernel, host mounts | Bad mounts, credentials, egress |
| Typical use | Reviewed local utilities | Repository builds and tests | Untrusted code, high impact |

## Six eval layers
type: concepts
from: phases/13-tools-and-protocols/27-skill-evals-packaging-and-portability/docs/en.md

- **Structure**: lint without a model. CI blocks `E_*` errors and allows reviewed `W_*` warnings.
- **Routing**: precision and recall over positives, clear negatives and near misses. Report raw counts.
- **Behavior**: baseline and treatment use the same model, tools, task and budget.
- **Scripts**: test outside model runs with empty, malformed and repeated input.
- **Safety**: record the control: instruction only, tool policy, approval, sandbox or verification.
- **Portability**: install into a clean destination. Validate the installed copy.
- **Verdicts**: `fixturePassed`, `localEvidenceReady`, `productionReady`. `passed` follows `productionReady`.

## Project pipelines
type: architecture
from: projects/skill-scanner/solution, projects/self-improving-skill-loop/solution

```arch
node | spans | 1,1 | spans | UTF-8 byte offsets | process
node | scan | 2,1 | scan | three named rules | process
node | score | 3,1 | risk_score | once per rule and line | process
node | review | 4,1 | review | review-required or below-threshold | client
node | split | 1,2 | split_cases | content and group union | store
node | eval | 2,2 | evaluate | per-case rows | process
node | prop | 3,2 | propose | dev errors, min_support 2 | process
node | gate | 4,2 | gate | gain and regressions | client
edge | spans | scan | lines
edge | scan | score | findings
edge | score | review | score
edge | split | eval | development
edge | eval | prop | errors
edge | prop | gate | candidate
```

## Tasks in code
type: task-table
span: 2
from: phases/13-tools-and-protocols/27-skill-evals-packaging-and-portability/code/main.py, phases/14-agent-engineering/10-skill-libraries-voyager/code/main.py, projects/self-improving-skill-loop/solution

| Task | Code |
|---|---|
| Lint a bundle | `lint_package(root)` |
| Score routing | `classification_metrics(expected, predicted)` |
| Check an installed copy | `verify_manifest(root, expected)` |
| Host support matrix | `portability_matrix(requirements, hosts)` |
| Split without leakage | `split_cases(cases, holdout_fraction=0.25)` |
| Propose rules | `propose(development, rules, min_support=2)` |
| Gate a candidate | `gate(holdout, baseline, candidate)` |
| Refine a library skill | `register(skill, dedup=True)` bumps the version |

## Questions
type: qa
span: 2
from: phases/13-tools-and-protocols/26-skill-permissions-sandboxes-and-trust/docs/en.md, projects/skill-scanner/README.md, phases/14-agent-engineering/10-skill-libraries-voyager/docs/en.md, projects/self-improving-skill-loop/stages/04-promotion/docs/en.md

- **Does `allowed-tools` sandbox a skill?** No. It affects capability or permission prompts. It is not OS isolation.
- **Does a hash prove a package is safe?** No. It proves that the bytes match a manifest.
- **Is a below-threshold scan safe?** No. Only these rules did not cross the threshold.
- **Why version skills?** A parent pinned to v1 does not pick up a refined v3.
- **Why rotate the holdout?** Repeated tuning on the same holdout leaks information.
Code and artifacts 1
What you take away

Saved in your notebook on this device.

Sources and limits

Reading checkpoints are self-reported. Test results are recorded separately and apply to the executed cases.

AI Engineering from Scratch · 3f9715c · MIT

Download this file ↓