[eric] skills: an export never ships a venv, and a licence id is not an API key (ENG-401)

Both halves diagnosed by Haik Decie.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018foyDoK19jjbYdudfzQVkZ
This commit is contained in:
ciregenz
2026-08-24 11:38:26 -07:00
co-authored by Claude Opus 5
parent 2e8d431118
commit dc014c5377
4 changed files with 86 additions and 2 deletions
+12 -1
View File
@@ -7,6 +7,8 @@ but the body still rides the central scrub in case someone pasted a token in."""
from __future__ import annotations
import os
from backend.apps.outputs.workspace_io import WALK_SKIP_DIRS
import shutil
from backend.apps.skills import skills as store
@@ -95,9 +97,18 @@ class SkillExportable:
def p_read_supporting_files(skill_dir: str) -> dict[str, bytes]:
"""Every file in a skill folder except SKILL.md, as {relpath: bytes}."""
"""Every file in a skill folder except SKILL.md, as {relpath: bytes}.
Prunes the same build/venv dirs the app exporter has always pruned. This walker bound `dirs`
and never used it, so exporting a skill with a Python venv swept every file under `.venv/` into
the bundle: a python3.13 tree with absolute paths baked in, dead on any other machine, and big
enough that one vendored SPDX licence list tripped the secret scanner and hard-blocked the
export with advice ("remove the secret") that no user could follow. Credit: Haik Decie, who
diagnosed both halves.
"""
out: dict[str, bytes] = {}
for root, p_dirs, names in os.walk(skill_dir):
p_dirs[:] = [d for d in p_dirs if d not in WALK_SKIP_DIRS]
for n in names:
full = os.path.join(root, n)
rel = os.path.relpath(full, skill_dir)
+5 -1
View File
@@ -15,7 +15,11 @@ REDACTED = "[redacted]"
# Literal-secret shapes someone might paste into a file, skill body, or setting.
SECRET_SHAPE_PATTERNS = (
re.compile(r"sk-ant-[A-Za-z0-9_\-]{16,}"),
re.compile(r"sk-[A-Za-z0-9_\-]{16,}"),
# A real sk- key carries a long DASHLESS run; dashes were counted as key material, so the SPDX
# licence id "Asterisk-linking-protocols-exception" read as an OpenAI key and hard-blocked a
# skill export with advice ("remove the secret") that no user could act on. Requiring the run
# keeps every real shape (sk-proj-<48>, sk-ant-api03-<95>) and drops dictionary-words-with-dashes.
re.compile(r"sk-[A-Za-z0-9_\-]*[A-Za-z0-9_]{20,}"),
re.compile(r"AIza[A-Za-z0-9_\-]{20,}"), # Google API key shape
re.compile(r"gh[pousr]_[A-Za-z0-9]{20,}"), # GitHub tokens
re.compile(r"Bearer\s+[A-Za-z0-9._\-]{16,}"),
+34
View File
@@ -0,0 +1,34 @@
"""The scanner blocks an export, so a false positive costs the user something they cannot fix.
Reported by Haik Decie: exporting a skill failed with "a secret-shaped value is in
.../packaging/licenses/_spdx.py; remove it" and there was no secret to remove. The SPDX licence id
`Asterisk-linking-protocols-exception` contains `sk-linking-protocols-exception`, and the pattern
counted dashes as key material.
"""
from backend.common.secret_scan import looks_secret, redact_secret_shapes
def test_a_licence_identifier_is_not_a_key():
assert looks_secret("Asterisk-linking-protocols-exception") is False
assert looks_secret("sk-linking-protocols-exception") is False
def test_real_key_shapes_are_still_caught():
# The control that keeps this from being a blanket weakening.
assert looks_secret("sk-proj-" + "a1B2c3D4e5F6g7H8i9J0k1L2m3N4o5P6q7R8s9T0") is True
assert looks_secret("sk-ant-api03-" + "x" * 95) is True
assert looks_secret("sk-" + "A1b2C3d4E5f6G7h8I9j0K1l2") is True
assert looks_secret("AIza" + "B" * 30) is True
assert looks_secret("ghp_" + "c" * 30) is True
def test_other_dictionary_dashed_words_stay_clear():
for benign in ("task-list-runner-exception", "disk-usage-report-helper",
"risk-scoring-model-weights", "sk-a-b-c-d-e-f"):
assert looks_secret(benign) is False, benign
def test_redaction_still_removes_a_real_key():
out = redact_secret_shapes("key=sk-proj-" + "z" * 40)
assert "sk-proj-" not in out and "[redacted]" in out
+35
View File
@@ -0,0 +1,35 @@
"""A skill export must not ship a venv.
Reported by Haik Decie: exporting a skill with a Python venv failed on a secret-shaped value inside
`.venv/.../packaging/licenses/_spdx.py`. Two stacked bugs; this pins the root cause. The walker
bound `dirs` and never pruned it, so it swept a python3.13 tree with absolute paths baked in, dead
on any other machine, into the bundle. The app exporter has always pruned the same set.
"""
import os
from backend.apps.swarm.entities.skills import p_read_supporting_files
from backend.apps.outputs.workspace_io import WALK_SKIP_DIRS
def test_a_venv_never_reaches_the_bundle(tmp_path):
skill = tmp_path / "s"
(skill / ".venv" / "lib" / "python3.13" / "site-packages").mkdir(parents=True)
(skill / ".venv" / "lib" / "python3.13" / "site-packages" / "_spdx.py").write_text("x")
(skill / "node_modules").mkdir()
(skill / "node_modules" / "big.js").write_text("x")
(skill / "helper.py").write_text("real content")
(skill / "SKILL.md").write_text("# skill")
out = p_read_supporting_files(str(skill))
assert "helper.py" in out, "real supporting files must still ship"
assert not any(".venv" in k for k in out), f"venv leaked: {list(out)}"
assert not any("node_modules" in k for k in out)
assert "SKILL.md" not in out
def test_it_prunes_the_same_set_the_app_exporter_does():
# One definition of "do not ship this", not two that can drift.
src = open("backend/apps/swarm/entities/skills.py").read()
assert "WALK_SKIP_DIRS" in src
assert ".venv" in WALK_SKIP_DIRS and "node_modules" in WALK_SKIP_DIRS