feat(pypi): wire VC-002L import-time detection at advisory (D-166) - #139
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.pyclass of gap end to end (payload in an ordinary runtime module that runs onimport).Changes (four layers, each tested)
internal/ecosystem/pypi/sdist.go: retains runtime.pymodules from both the sdist tar and the wheel zip, under new count/byte caps (maxModuleFiles/maxModuleTotalBytes) and anisRuntimeModulefilter (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.installsurface.go: runsAnalyzePythonLoadTimeover the retained modules for every dependency (sdist + wheel-only paths); discloses the unexamined import surface asGapTruncatedcoverage gaps.pyloadtime.go: hook namemodule-load:→import-time:(to stay separable from npm'smodule-load:); module cap raised for whole-package scanning.VC-002Lcheck (registered, medium/advisory). The ceiling is structural: the block-class VC-002 family (collectHooks) excludesimport-time:hooks, so a credential+network import-time hook cannot reach VC-002d and block. Scoped to theimport-time:name — npm'smodule-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
module-load:still gates via VC-002d (exclusion didn't over-reach).__main__guard) still clean.Validation
go test ./...all pass ·go vetclean ·go buildok · new/modified Go files gofmt-clean.depsnort checksshowsVC-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