Skip to content

feat(pypi): wire VC-002L import-time detection at advisory (D-166) - #139

Merged
MoSLoF merged 1 commit into
mainfrom
feat/vc002l-wiring
Aug 30, 2026
Merged

feat(pypi): wire VC-002L import-time detection at advisory (D-166)#139
MoSLoF merged 1 commit into
mainfrom
feat/vc002l-wiring

Conversation

@MoSLoF

@MoSLoF MoSLoF commented Aug 30, 2026

Copy link
Copy Markdown
Collaborator

Intent

Meet the rest of the VC-002L spec (D-165): the Python import-time module surface is now enumerated, analyzed, and reported as an advisory finding — closing the telnyx/_client.py class of gap end to end (payload in an ordinary runtime module that runs on import).

Changes (four layers, each tested)

  1. Module enumerationinternal/ecosystem/pypi/sdist.go: retains runtime .py modules from both the sdist tar and the wheel zip, under new count/byte caps (maxModuleFiles / maxModuleTotalBytes) and an isRuntimeModule filter (excludes setup.py, conftest.py, test/docs/build trees, packaging metadata). Exceeding a cap → ModulesTruncated (partial disclosed coverage), never a silent drop. Cache semantics v3 → v4 so a stale record carrying no modules can't read as a clean import surface.
  2. Adapterinstallsurface.go: runs AnalyzePythonLoadTime over the retained modules for every dependency (sdist + wheel-only paths); discloses the unexamined import surface as GapTruncated coverage gaps.
  3. Analyzerpyloadtime.go: hook name module-load:import-time: (to stay separable from npm's module-load:); module cap raised for whole-package scanning.
  4. Check + advisory ceiling — new VC-002L check (registered, medium/advisory). The ceiling is structural: the block-class VC-002 family (collectHooks) excludes import-time: hooks, so a credential+network import-time hook cannot reach VC-002d and block. Scoped to the import-time: name — npm's module-load: hooks are untouched, so VC-002j (OPU-31) still gates.

Security semantics

Advisory-only, and structurally enforced (family exclusion, not just a gate constant) per D-165. No change to any existing detection: npm load-time gating, the VC-002 family, and all other checks are untouched. Coverage stays honest — truncated module trees and the deferred wheel/root cases are disclosed gaps or documented deferrals, never clean results.

Adversarial / FP review

  • Family-exclusion test: VC-002d does not fire on an import-time exfil hook; VC-002L surfaces it advisory.
  • Scoping test: npm module-load: still gates via VC-002d (exclusion didn't over-reach).
  • Analyzer's 7 benign FP controls (env read, embedded-data decode, subprocess probe, plugin registry, uncalled helper, __main__ guard) still clean.

Validation

go test ./... all pass · go vet clean · go build ok · new/modified Go files gofmt-clean. depsnort checks shows VC-002L … medium … advisory.

Remaining limitations (deferred)

Root-local import surface; payload-in-wheel-not-sdist for dual-shipping packages; raising the emit threshold past capability-combinations (spec §7 corpus eval). Promotion above advisory is gated on that evaluation.

🤖 Generated with Claude Code

Meet the rest of the VC-002L spec (D-165): the Python import-time module surface is now enumerated, analyzed, and reported as an advisory finding. Closes the telnyx/_client.py class of gap end to end.

Module enumeration: the sdist fetcher now retains runtime .py modules from BOTH the sdist tar and the wheel zip, under new count/byte caps (maxModuleFiles/maxModuleTotalBytes) and an isRuntimeModule filter (excludes setup.py, conftest.py, test/docs/build trees, packaging metadata). Exceeding a cap degrades to ModulesTruncated (partial disclosed coverage), never a silent drop. Cache semantics bumped v3->v4 so a stale record carrying no modules cannot read as a clean import surface.

Adapter: installsurface.go runs AnalyzePythonLoadTime over the retained modules for every dependency (sdist and wheel-only paths) and discloses the unexamined import surface as GapTruncated coverage gaps. Root-local module scanning is deferred (documented).

Check + advisory ceiling: new VC-002L check (registered) surfaces import-time: hooks at medium/advisory. The ceiling is structural, not just a gate constant — the block-class VC-002 family (collectHooks) EXCLUDES import-time: hooks, so a credential+network import-time hook cannot reach VC-002d and block. The exclusion is scoped to the import-time: name; npm's module-load: hooks are untouched, so VC-002j (OPU-31) still gates. The analyzer's hook name was changed module-load: -> import-time: to keep the two separable.

Tests: sdist module extraction + retention cap; VC-002L fires advisory; the family exclusion (VC-002d does not fire on an import-time exfil hook) and its scoping (npm module-load still gates). go test ./... green, vet clean, build ok; new files gofmt-clean.

Deferred (spec §7 / follow-ups): root-local import surface, payload-in-wheel-not-sdist for dual-shipping packages, raising the emit threshold past capability-combinations. Promotion above advisory is gated on the corpus evaluation, not this wiring.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@MoSLoF
MoSLoF merged commit 781bccd into main Aug 30, 2026
11 checks passed
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.

1 participant