How the resolve_input Node Normalizes Input Sources in SkillSpector

The resolve_input node converts diverse skill sources—Git repositories, ZIP archives, URLs, or local files—into a standardized local directory path while enforcing security checks against SSRF and zip-slip attacks.

The resolve_input node serves as the entry point for NVIDIA's SkillSpector analysis pipeline. Located in src/skillspector/nodes/resolve_input.py, this node transforms whatever input the user provides into a predictable local directory structure that downstream nodes can scan. It handles the complexity of remote cloning, downloading, and extraction so the rest of the graph works with a normalized skill_path.

Core Functionality and Data Flow

State-Based Input Processing

The node accepts a SkillspectorState object (defined in src/skillspector/state.py) containing an input_path field. According to the implementation in resolve_input.py lines 34-71, the function signature is:

def resolve_input(state: SkillspectorState) -> dict[str, object]:

When input_path is present, the node instantiates an InputHandler and calls its resolve() method (lines 46-50). This handler determines whether the input is a Git URL, raw file URL, ZIP archive, single file, or existing directory.

Return Value Structure

The node returns a dictionary containing two critical keys:

  • ** skill_path**: The absolute path to the prepared directory ready for analysis
  • ** temp_dir_for_cleanup**: The temporary directory path for post-analysis cleanup, or None if the input was already local

As implemented in lines 50-56 of resolve_input.py, the node captures temporary directories created during resolution to ensure proper cleanup later.

Input Type Resolution and Security Architecture

Supported Source Types

The InputHandler.resolve() method in src/skillspector/input_handler.py (lines 89-119) categorizes inputs and performs specific operations:

  • Git URLs: Shallow clone into a temporary directory
  • Raw file URLs: Download and optionally unzip into a temp directory
  • ZIP files: Safe extraction into a temporary workspace
  • Single files: Copy into a temporary directory
  • Directories: Resolve to absolute path without copying

Security Safeguards

Before any filesystem operations, the handler enforces three security layers:

  1. Allowed Hosts Whitelist: Only approved Git hosts (github.com, gitlab.com, bitbucket.org) and download sources (raw.githubusercontent.com, huggingface.co) are permitted
  2. SSRF Protection: The _is_private_ip check (lines 61-78 in input_handler.py) resolves hostnames and rejects private, loopback, link-local, or reserved IP addresses
  3. Zip-Slip Mitigation: Each entry in ZIP archives is validated to stay within the extraction directory before writing (lines 38-45 in input_handler.py)

Practical Usage Examples

Direct Node Invocation

from skillspector.state import SkillspectorState
from skillspector.nodes.resolve_input import resolve_input

# Scan a public Git repository

state = SkillspectorState({"input_path": "https://github.com/example/my-skill.git"})
result = resolve_input(state)

# Returns: {"skill_path": "/tmp/skillspector_abcdef/repo", 

#           "temp_dir_for_cleanup": "/tmp/skillspector_abcdef"}

Handling Local Archives


# Process a local ZIP file

state = SkillspectorState({"input_path": "/home/user/my_skill.zip"})
result = resolve_input(state)
print(result["skill_path"])

# Output: "/tmp/skillspector_12345/extracted"

Pipeline Integration

When used within the full SkillSpector graph orchestrated by src/skillspector/graph.py, the node automatically handles the first transformation step:

from skillspector.graph import run_graph

state = {"input_path": "https://huggingface.co/datasets/example_skill.zip"}
output = run_graph(state)  # Internally calls resolve_input first

print(output["skill_path"])

Summary

  • The resolve_input node in src/skillspector/nodes/resolve_input.py serves as the unified entry point for all skill sources in the SkillSpector pipeline
  • It delegates actual resolution logic to the InputHandler class in src/skillspector/input_handler.py
  • The node returns a normalized skill_path and tracks temporary directories via temp_dir_for_cleanup for proper resource management
  • Security checks including host whitelisting, SSRF prevention, and zip-slip protection run before any filesystem modifications
  • The implementation handles Git clones, URL downloads, ZIP extraction, and local directory resolution through a single consistent interface

Frequently Asked Questions

What happens if the input_path is missing or empty?

If the state lacks an input_path but contains a skill_path, the node normalizes the existing path to an absolute path using Path(skill_path).resolve() (lines 60-66 in resolve_input.py). If neither field is present, the node returns {"skill_path": None, "temp_dir_for_cleanup": None}, allowing downstream nodes like build_context to raise user-friendly error messages.

How does SkillSpector prevent malicious ZIP files from overwriting system files?

The InputHandler implements zip-slip mitigation by validating each entry path in input_handler.py lines 38-45. Before extraction, it resolves the absolute path of each ZIP entry and verifies it remains within the intended extraction directory, preventing directory traversal attacks that attempt to write to parent directories or system paths.

Can resolve_input handle private Git repositories or internal URLs?

The current implementation restricts remote sources to whitelisted hosts including github.com, gitlab.com, bitbucket.org, and specific download domains. As implemented in input_handler.py lines 61-78, the code performs SSRF checks that block private IP ranges, meaning internal or private Git repositories would require modification of the allowed hosts list or use of local directory inputs instead.

Is the temporary directory automatically cleaned up after analysis?

The resolve_input node returns the temporary directory path via temp_dir_for_cleanup (lines 50-56 in resolve_input.py), but the cleanup responsibility lies with the graph orchestrator or the calling code. The node ensures the path is available for cleanup operations but does not perform the deletion itself, allowing downstream nodes to complete their analysis before resources are released.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →