Skip to content

Harden the inspector, broaden tests, and reconcile docs (self-audit fixes)#2

Merged
zztimur merged 8 commits into
mainfrom
claude/skill-forge-audit-xb3tof
Jul 9, 2026
Merged

Harden the inspector, broaden tests, and reconcile docs (self-audit fixes)#2
zztimur merged 8 commits into
mainfrom
claude/skill-forge-audit-xb3tof

Conversation

@zztimur

@zztimur zztimur commented Jul 9, 2026

Copy link
Copy Markdown
Owner

Summary

Self-audited skill-forge with its own methodology, then fixed every finding. This addresses 2 High, 14 Medium, 12 Low, and 4 Nit issues across the inspector, self-tests, CI, SKILL.md, and the reference docs. Each inspector change ships with a regression test.

The headline problem was that the inspector failed good skills: it counted .git internals toward strict limits, treated a documented command like `scripts/tool.py --json` as a missing resource, and rejected valid frontmatter (BOMs, optional keys). Those false-positives are gone, release CI now enforces the gate, and the self-test suite grew from 25 to 58 cases.

What changed, by commit

  • Exclude VCS/junk dirs; fix backtick resource capture — stop scanning .git/node_modules/etc. (adds excluded_directories); stop backtick refs at whitespace so documented commands aren't false missing_resource_reference. (H1, H2)
  • Accept BOM, valid optional frontmatter keys, block-scalar content — decode utf-8-sig; recognize license/allowed-tools/metadata/version; keep #/blank lines inside |/> scalars. (M2, M4, L1)
  • Harden ZIP handling; flag destructive shell commands — flat-zip → warning with a meaningful name; pre-open size gate against memory-exhaustion; case-collision detection; heuristic script_dangerous_command for shell installers. (M3, M9, L3, M13)
  • Dedupe aliased metadata counts; document all emitted codesiter_findings dedupes by identity so aliased findings count once; schema doc now documents every emitted code (verified bidirectionally). (L2, L12)
  • Broaden self-tests — severity assertions, a SKIP path for unprivileged symlinks, stderr checks, markdown-renderer coverage, and fixtures for previously-untested codes (48/63 now exercised). (M14, L9, N4)
  • Run the strict gate in release CI; test min Python — release workflow runs the suite + strict-inspects the built artifact and blocks on dangerous commands; self-tests run on a 3.9/latest matrix. (M10, L10)
  • Make SKILL.md self-sufficient — new 198-char trigger-aware description; decidable validator step; python3 examples; non-negotiable safety-floor rule; self-contained repair/containment/redirect guidance. (M1, M5, M6, M12, L4, L5, L8, N3)
  • Reconcile references, README, metadata — rewrite example-report.md to match the template; add reserved-name/64-char rules; script-safety gate; de-dup policy prose; README tree + release-workflow docs; remove stale .gitattributes entries; formatting nits. (M7, M8, M11, L6, L7, L13, N1, N2)
  • Release-notes generator — dependency-free scripts/generate_release_notes.py wired into the release workflow (export-ignored from the shipped zip).

Verification

  • Self-tests: 58/58 (SKIP path works; severity assertions have teeth)
  • skill-forge strict-passes its own inspector; .git excluded (file_count 84 → 20)
  • Every originally-failing §7 probe (git tree, BOM, flat zip) now passes; each inspector fix verified to fail its test when reverted
  • Emitted finding codes ↔ schema doc agree in both directions
  • Release dry-run: built artifact strict-passes, dangerous-command gate clean, notes generate
  • All scripts parse under Python 3.9

🤖 Generated with Claude Code


Generated by Claude Code

claude added 8 commits July 9, 2026 01:57
The inspector walked .git (and node_modules, .venv, __pycache__,
.pytest_cache), so auditing a git working tree counted git internals toward
directory limits, inflated file/size counts, and exposed .git/config to the
secret scan. Skip these directories during traversal and report which were
skipped via a new excluded_directories output field.

Separately, the backtick branch of RESOURCE_REF_PATTERN captured everything up
to the closing backtick, so a documented command like `scripts/tool.py --json`
was extracted as a nonexistent path, producing a false missing_resource_reference
(and marking the real script orphaned). Stop the capture at whitespace and keep
only the first token defensively.

Add regression tests covering a git working tree with a planted secret and 1200
loose objects, and a SKILL.md that documents its helper script with command
flags. Self-tests: 27/27.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P1WmZkinHbJxST6dn5xeos
Three frontmatter-robustness fixes so the inspector stops rejecting valid
skills:

- Decode text with utf-8-sig, so a SKILL.md with a leading UTF-8 BOM (common
  from Windows editors) parses instead of failing frontmatter_missing_or_invalid.
- Recognize license, allowed-tools, metadata, and version as optional
  platform keys (info-level) instead of error-level unexpected keys; genuinely
  unknown keys still error.
- Preserve '#'-prefixed and blank lines as literal content inside YAML block
  scalars (| and >), so a multiline description is not silently truncated and
  description_length is accurate.

Add regression tests for a BOM SKILL.md, BOM+CRLF, optional platform keys, an
unknown-key guard, and a block scalar with a '#' line and a blank line.
Self-tests: 32/32.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P1WmZkinHbJxST6dn5xeos
- Flat zips (SKILL.md at the archive root, no wrapping folder) now produce a
  warning-level zip_missing_top_level_skill_folder whose expected value is the
  skill name, instead of an error whose expected value was the random temp
  extraction dir name.
- Gate the on-disk archive size before opening the zip. zipfile parses the
  entire central directory into memory at open() time, so a crafted archive
  with very many members could drive memory up before any per-member limit
  fired; the size cap now bounds that. package_zip_too_large moves entirely to
  this pre-open gate so folder and zip size checks never double-report.
- Detect members that collide only by case (File.txt vs file.txt), which
  silently overwrite on case-insensitive filesystems, via zip_case_collision_member.
- Add a heuristic, warning-level script_dangerous_command scan over bundled
  shell scripts (curl|bash installers, rm -rf of root/home, fork bombs, dd to
  /dev, mkfs). Shell-script-only to avoid false positives on docs and source.

Add regression tests for all four. Self-tests: 36/36.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P1WmZkinHbJxST6dn5xeos
- iter_findings now dedupes by object identity, so an OpenAI-metadata finding
  exposed under both platform_metadata_findings and its backward-compatible
  agent_metadata_findings alias (the same list object) is counted once in
  summary.error_count/warning_count/finding_count instead of twice.
- inspector-output-schema.md now documents every emitted finding code: the
  previously-missing zip_read_error, directory_root_lstat_failed,
  directory_root_resolve_failed, directory_file_stat_failed, frontmatter_unavailable,
  package_zip_too_large, and package_folder_large, plus the codes added in this
  branch (zip_missing_top_level_skill_folder, zip_case_collision_member,
  script_dangerous_command). Also documents the excluded_directories,
  dangerous_command_findings, and dangerous_command_note output fields, the
  expected/actual/keys evidence fields, and the expanded optional-keys set.

Emitted codes and the schema doc are now in exact agreement in both directions.
Add a regression test asserting the aliased finding is counted once.
Self-tests: 37/37.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P1WmZkinHbJxST6dn5xeos
Grow the regression suite from 37 to 58 cases and strengthen the harness:

- Assert finding severity (not just presence) via a new expected_severity, so
  an error->warning downgrade is caught even when the strict exit code is
  unchanged. Backfilled on the single-code cases.
- Add a SkipCase path: the folder-symlink fixtures now SKIP (not abort the
  suite) on platforms where os.symlink is unprivileged.
- Assert stderr content for the invalid-limit case so it cannot silently pass
  for the wrong reason.
- Exercise the markdown renderer on a findings-rich fixture (not just the
  zero-finding footer).

New coverage for previously-untested codes: openai_metadata_missing_interface
/ missing_display_name / unreadable, missing_resource_reference, the .env.*
suspicious-filename variant, all remaining secret-content rules (private key,
github, slack, google service account, jwt, api-key, password), bounded-read
truncation, package_folder_large, corrupt zip, and several frontmatter/size
limit codes. 48 of 63 emittable codes are now exercised; the rest require
injected filesystem errors or are emission-covered.

Fake secrets in fixtures are constructed by concatenation so this test file's
own source contains no literal secret pattern (verified: skill-forge strict-
passes its own inspector). Self-tests: 58/58.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P1WmZkinHbJxST6dn5xeos
- The release workflow now runs the regression suite and strict-inspects the
  built skill-forge.zip before publishing, and refuses to release if strict
  inspection fails or a bundled shell script trips script_dangerous_command.
  Previously it only grepped the archive listing for two filenames.
- The self-tests workflow runs on a Python version matrix (3.9 and latest
  stable) so a regression on the minimum supported interpreter is caught, not
  just on the newest. All scripts are verified to parse under 3.9.
- Document the Python 3.9+ floor in README and use python3 in its inspector
  example.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P1WmZkinHbJxST6dn5xeos
- Rewrite the frontmatter description (198 chars) to sentence-case, add the
  "Review"/"QA" trigger verbs and an explicit "diagnose triggering" hook for
  the skill's flagship capability, and capitalize the proper nouns. Passes the
  skill's own frontmatter heuristics.
- Make the official-validator step decidable: name concrete candidates and a
  discovery procedure, and state the fallback when none is found, instead of an
  unlocatable "if available" condition tied to a Critical severity.
- Use python3 in all command examples with a python fallback note; document the
  Python 3.9+ floor.
- Add a non-negotiable safety-floor standard so secret/unsafe findings are
  always reported even when the user narrows scope.
- Give the repair path a self-contained fallback (edit, re-inspect --strict,
  repackage) instead of pointing at an undefined external workflow.
- Add a positive containment procedure for running bundled scripts, and
  wrong-input-type redirect guidance for non-skill inputs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P1WmZkinHbJxST6dn5xeos
- Rewrite example-report.md to follow report-template.md's exact 11-section
  structure and its 6-column, 11-category pressure-test table (was 10 sections
  with a 3-column, 5-row table), so the executive-report path and the mandated
  template no longer disagree.
- Add the reserved-name and 64-character name rules to platform-compatibility.md,
  which SKILL.md step 4 directs reviewers to consult.
- Add a release gate for destructive/network-piping commands in bundled scripts
  (script_dangerous_command), and note the overlap between the release-gate and
  audit checklists so shared items are verified once.
- De-duplicate policy prose: SKILL.md relays the inspector's secret_scan_note
  instead of restating it, and defers the 11/10 criteria to the rubric that
  owns them.
- Disambiguate the near-duplicate audit-checklist bullets by moving the
  inspector-output check into Validation Evidence.
- Use python3 in the README and schema-doc examples; add release-skill.yml and
  .gitattributes to the README tree and describe the release workflow.
- Remove stale export-ignore entries (tests/, README.dev.md) and fix
  heading-case and double-blank-line formatting nits.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P1WmZkinHbJxST6dn5xeos
@zztimur zztimur merged commit 7db1639 into main Jul 9, 2026
4 checks passed
@zztimur zztimur deleted the claude/skill-forge-audit-xb3tof branch July 9, 2026 04:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants