Specification Generator
Relevant source files
The following files were used as context for generating this wiki page:
The Specification Generator is a critical component of the numan-plugins build pipeline responsible for emitting numan-registry package specifications. It consumes metadata from the project's central manifest and machine-readable output from packaging scripts to produce a JSON specification that defines how a plugin should be intaken by the registry.
Its primary purpose is to bridge the gap between built binary artifacts and the signed registry index. It preserves immutable provenance, such as upstream Git commits and source repository URLs, while intentionally omitting sensitive data like SHA-256 hashes, which are independently verified by the registry during intake to maintain the trust boundary.
Sources: scripts/gen_spec.py:2-15, README.md:27-33
Core Logic and Data Flow
The generator operates by aggregating data from multiple sources to construct a comprehensive kind: binary artifact specification. It validates that every expected target platform for a given plugin version has a corresponding packaged artifact.
The diagram above shows the data flow from input files through validation steps to the final specification output.
Input Requirements
The generator requires four primary inputs to function:
- Plugin Name: The identifier used to look up the entry in the
active[]list ofmanifest.json. - Packaged Records: A TSV file containing
PACKAGEDrows generated bypackage_plugin.py. Each row includes the target triple, filename, SHA-256 hash, and internal executable path. - Asset Directory: The local path where the packaged
.tar.gzor.zipfiles are stored for verification. - Release Base URL: The GitHub Releases URL where the assets will be hosted.
Sources: scripts/gen_spec.py:19-33, scripts/package_plugin.py:100-101
Functional Components
Manifest Integration
The generator utilizes load_manifest_entry to extract metadata from manifest.json. This includes information such as the plugin owner, description, version, and supported nu_version range. It also retrieves source_commit and plugin_bin (the cargo binary name) to populate the source block for provenance tracking.
Sources: scripts/gen_spec.py:44-64, manifest.json:16-30
Artifact Validation
Before generating the specification, the tool performs strict validation:
- Target Parity: It compares the targets found in the packaged TSV against the
expected_targetsderived from the manifest (taking into account anyexclude_targets). - Hash Verification: It re-computes the SHA-256 hash of each local asset file and compares it against the hash provided in the packaged TSV to ensure consistency before the specification is emitted.
Sources: scripts/gen_spec.py:102-114, scripts/gen_spec.py:129-144, scripts/validate_manifest.py:53-73
Specification Schema
The resulting JSON follows the numan-registry schema for plugins. It categorizes information into metadata, provenance, and artifact targets.
| Field Group | Description | Source File Reference |
|---|---|---|
| Metadata | Name, owner, description, version, tags, and compatibility. | [scripts/gen_spec.py:157-167](https://github.com/numan-cli/numan-plugins/blob/ab07b7c39c6fe5601e0465f8241bd6a98c940aef/scripts/gen_spec.py#L157-L167) |
| Source | Git URL, immutable rev (commit SHA), and cargo_name. | [scripts/gen_spec.py:168-172](https://github.com/numan-cli/numan-plugins/blob/ab07b7c39c6fe5601e0465f8241bd6a98c940aef/scripts/gen_spec.py#L168-L172) |
| Artifact | Defines kind: binary and a map of target triples to URLs and executable paths. | [scripts/gen_spec.py:173-177](https://github.com/numan-cli/numan-plugins/blob/ab07b7c39c6fe5601e0465f8241bd6a98c940aef/scripts/gen_spec.py#L173-L177) |
Technical Implementation Details
Provenance Preservation
A key architectural invariant is that provenance is emitted as a top-level source block. This ensures that the registry index retains a link to the exact immutable upstream commit used for the build, even if the human-facing tag changes or is deleted.
# From build_spec in scripts/gen_spec.py
return {
# ... metadata ...
"source": {
"git": f"https://github.com/%7Bentry%5B%27repo%27%5D%7D%22%2C
"rev": entry["source_commit"],
"cargo_name": entry["plugin_bin"],
},
"artifact": {
"kind": "binary",
"targets": {k: targets[k] for k in sorted(targets)},
},
}
Sources: scripts/gen_spec.py:168-177, scripts/test_gen_spec_source.py:44-53
Trust Boundary and Hashing
The gen_spec.py script intentionally excludes SHA-256 hashes from the final output JSON. This design decision enforces the trust boundary: the numan-registry intake scripts are responsible for downloading the published assets and computing hashes themselves, preventing hand-typed or potentially tampered hashes from entering the signed registry index.
Sources: scripts/gen_spec.py:10-12, README.md:29-33
Conclusion
The Specification Generator ensures that the build pipeline produces standardized, validated, and high-provenance metadata for every plugin. By verifying local hashes and target lists before outputting the specification, it acts as a final safety gate before artifacts are handed off to the numan-registry for signing and publication.
Sources: scripts/gen_spec.py:179-204, REVIEW.md:55-63