An extensible framework for the rapid detection and profiling of potential supply-chain attacks of libraries hosted on code repositories.
Project description
solorider
(pronounced "Solo Rider")
An extensible framework for the rapid detection and profiling of supply-chain attacks in code repositories.
solorider allows security practitioners to efficiently iterate on the detection and profiling of potential supply-chain attacks of libraries hosted on code repositories. solorider provides facilities to assess packages across npm, GitHub, PyPI and make critical decisions on a package's integrity -- or -- adapt to shifts in actor tradecraft.
The project was authored to address three primary security/intelligence questions:
1. Is this package potentially compromised?
2. Are any of this package's dependencies compromised?
3. Am I compromised?
solorider is a proof-of-concept and comes with no warranties or guarantees.
Installation
# Install from PyPI
pip install solorider
To install from source instead:
git clone https://github.com/matonis/solorider.git
cd solorider
pip install .
# Development mode (editable)
pip install -e .
# Verify
solorider --list-plugins
Quick Start
import solorider
d = solorider.SupplyChainDetector()
d.assess_package('cap-js-postgres-2.2.2')
d.print_reports()
Output:
[solorider] 'cap-js-postgres-2.2.2' identified in 1 ecosystem(s): npm
[solorider] Proceeding to download and analyze...
[solorider] Analysis complete.
============================================================
[npm] cap-js-postgres-2.2.2-npm-1781719850
============================================================
Report 1 (standard_report): solorider default summary
[!] - This package had detections that may need review
[!] - There were multiple detections on this package which may need to be reviewed
[+] - package/execution.js
[!] (high) - (yara_detector|general_LargeFile): File is anomalously large
[!] (high) - (yara_detector|general_ObfuscatorPattern): Determines if uses obfuscation
[!] (high) - (yara_detector|session_CookieTheft_AWS): Matches AWS credential/cookie theft patterns
[!] (high) - (yara_detector|session_CookieTheft_ExfilIndicator): Matches data-exfiltration indicators
[!] (medium) - (anomalous_size|anomalous_file_size): File size is anomalous for this package
[+] - package/setup.mjs
[!] (high) - (yara_detector|all_bunArtifacts): Matches Bun runtime artifacts
[!] (medium) - (package_installer_detector|install_script): Declares an install lifecycle script
[+] - package/package.json
[!] (medium) - (package_installer_detector|scripts.preinstall): Declares a preinstall lifecycle script
Usage
solorider has three primary use cases.
1. Assess a Package
import solorider
d = solorider.SupplyChainDetector()
# Bare name -- probes all ecosystems (PyPI, npm, AUR, GitHub)
d.assess_package('lodash')
# Pinned PyPI version
d.assess_package('flask==3.0.3')
# Pinned npm version
d.assess_package('express@5.2.1')
# Scoped npm package
d.assess_package('@babel/parser@7.18.4')
# GitHub URL
d.assess_package('https://github.com/pallets/flask.git')
# AUR URL
d.assess_package('https://aur.archlinux.org/yay.git')
# Local compressed file
d.assess_package('/tmp/suspicious_package.tar.gz')
2. Assess Dependencies
# Python dependencies from requirements.txt
d.assess_dependencies('requirements.txt')
# npm dependencies from package.json
d.assess_dependencies('package.json')
3. Audit Local Environment
solorider has multiple plugins to assess local code environments. Installed packages are enumerated and its code scanned across existing analyzer plugins.
# Audit installed Python packages
d.audit_local('python')
d.print_reports()
The npm audit plugin requires a target directory (a project root or a node_modules directory). To determine the project root to pass as the target, run:
$ npm prefix
/home/user/projects/my-app
# Audit installed npm packages under the project root reported by npm prefix
d.audit_local('npm', target='/home/user/projects/my-app')
d.print_reports()
4. CLI
solorider lodash
solorider flask==3.0.3
solorider https://github.com/pallets/flask.git
solorider /tmp/suspicious_package.tar.gz
solorider --deps requirements.txt
solorider --deps package.json
solorider --list-plugins
Plugin Options
List the available analyzer plugins, grouped by category in execution order:
import solorider
d = solorider.SupplyChainDetector()
d.list_plugins()
Output:
Version Extractors
==================
[+] npm_version_extractor
Extract package name and version from npm package.json.
[+] pypi_version_extractor
Extract package name and version from PyPI metadata files (wheel METADATA,
PKG-INFO, pyproject.toml).
[+] stated_pinned_version_extractor
Records the caller-supplied 'stated_pinned_version' argument onto the
report, if it was passed.
Classifiers
===========
[+] anomalous_size
Identify files whose size is 20% or more above the average file size across
the entire package.
[+] npm_bin_detector
NPM-derivative packages only. Determine if a 'bin' config is present in
package.json and mark the script files it exposes as executable commands.
[+] npm_gyp_detection
NPM-derivative packages only. Parses binding.gyp to determine whether node-
gyp will automatically execute a script on install, and flags the package
files it references.
[+] package_installer_detector
NPM-derivative packages only. Determine if lifecycle scripts are present and
marks executed scripts.
[+] similar_filenames
Identify files whose names are suspiciously similar to other files in the
same package using Levenshtein edit distance.
Static
======
[+] entropy_analysis
Computes per-file Shannon entropy and flags high-entropy files that indicate
obfuscated, packed, or encrypted content that signature rules miss.
[+] indicator_match
Matches each file in a package against a provided Python-list of indicators
via the 'indicators=' parameter
[+] yara_detector
Scans each file in a package with a set of YARA rules (additional rules
contained in a folder can be extended in the package via
'yara_rule_directory=' parameter)
Deep
====
[+] check_dependency_for_advisory_npm
Resolve a package's declared package.json dependencies and flag any that
appear as malware in the GitHub Advisory Database.
[+] check_dependency_for_advisory_pypi
Resolve a package's declared requirements.txt dependencies and flag any that
appear as malware in the OSV advisory database.
[+] claude_deobfuscator
Deep analysis plugin that sends files flagged with obfuscation patterns to
Claude for behavioral assessment.
Judgements
==========
[+] advisory_lookup_npm
Query the GitHub Advisory Database for known malware advisories affecting
the assessed npm package.
[+] advisory_lookup_pypi
Query the OSV advisory database for known malware advisories affecting the
assessed PyPI package.
[+] check_npm_version_mismatch
Compare the extracted package version against the highest version inferred
from the cached npm registry directory and flag a mismatch as potential
dist-tag abuse.
[+] check_pypi_version_mismatch
Compare the extracted package version against the highest version inferred
from the cached PyPI registry directory and flag a mismatch as potential
version redirection.
[+] pinned_version_blacklist
Checks the package's extracted and stated pinned-version specifiers against
a provided Python-list of blacklisted versions via the
'blacklisted_pinned_versions=' parameter
[+] standard_judgement
Judgement plugin which sets baseline thresholds to determine likelihood of a
package being malicious
Reporting
=========
[+] file_report
Adds d.print_file_reports(): lists every file with at least one detection
for each assessed ecosystem, annotating each path with its high/medium/low
detection counts. Files with no detections are omitted.
[+] report_by_file
Adds d.print_report_by_file(files): given a filename/path or list of them,
prints the filename, path, hashes, and the detections on each matching file
grouped by plugin category and ordered by severity.
[+] report_by_plugin
Adds d.print_report_by_plugin(plugins): given a plugin name or list of them,
prints -- per assessed ecosystem -- the unique list of file paths each named
plugin produced a detection on.
[+] report_by_severity
Adds d.print_report_by_severity(severities): given a severity level
(high/medium/low/other) or list of them, prints -- per assessed ecosystem --
the unique list of file paths detected at each level.
[+] simple_report
Adds d.print_simple_report(): prints a concise per-package summary
(detection counts by severity, malicious judgement count, and which plugins
triggered) for every assessed ecosystem.
[+] standard_report
Creates a verbose overview of detections identified in a project. Report is
accessible via print_reports().
List the audit plugins used by audit_local() to enumerate locally
installed packages:
d.list_audit_plugins()
Output:
Audit Plugins
=============
[+] npm
Audits npm packages installed under a node_modules tree, resolving each to a
pinned version (name@version) and the on-disk location of its source code.
Requires a target argument: the path to a node_modules directory or a
project root containing one (passed to run() or via dispatch('npm',
target)).
[+] python
Audits Python packages installed in the local environment, resolving each to
a pinned version (name==version) and the on-disk location of its source
code.
Indicator matching:
d.assess_package('lodash', indicators=['edb172e0c2c9...'])
Custom YARA rules directory:
d.assess_package('lodash', yara_rule_directory='/home/user/my_yara_rules')
Entropy threshold: override the bits/byte value at or above which entropy_analysis flags a file as likely obfuscated, packed, or encrypted (default 7.2).
d.assess_package('lodash', entropy_threshold=6.5)
Claude deep analysis:
d.assess_package('lodash', CLAUDE_API_KEY='sk-ant-api03-...')
GitHub Advisory Database lookups: solorider will evaluate a package's dependencies against known advisories. The npm advisory-lookup plugins query the GitHub Advisory Database for known malware affecting a package and its dependencies; supplying GITHUB_TOKEN authenticates those lookups, raising the rate limit from 60 to 5,000 requests per hour for higher-volume scans.
d.assess_package('express@5.2.1', GITHUB_TOKEN='ghp_...')
Pinned-version blacklist matching:
d.assess_package('guardrails-ai==0.10.1',
blacklisted_pinned_versions=['guardrails-ai==0.10.1', 'express@5.2.1'],
)
Combined:
d.assess_package('lodash',
indicators=['edb172e0...'],
yara_rule_directory='/home/user/my_yara_rules',
entropy_threshold=6.5,
blacklisted_pinned_versions=['guardrails-ai==0.10.1'],
CLAUDE_API_KEY='sk-ant-api03-...',
)
Report Modules
After running an assessment, call any of these report methods on the detector to print results to stdout.
Full per-plugin report (every detection on every file, grouped by ecosystem):
d.assess_package('lodash')
d.print_reports()
Concise per-package summary (detection counts by severity plus which plugins triggered):
d.print_simple_report()
Per-package list of files that have detections, each annotated with its high/medium/low counts and ordered by most detections first:
d.print_file_reports()
Detailed drill-down for one or more specific files (filename, path, hashes, and detections grouped by severity):
# Single file (string)
d.print_report_by_file('package/lodash.js')
# Several files (list of strings)
d.print_report_by_file(['index.js', 'package/at.js'])
Per-plugin list of the unique files each named plugin detected (a plugin name string or a list of them):
# Single plugin (string)
d.print_report_by_plugin('yara_detector')
# Several plugins (list of strings)
d.print_report_by_plugin(['yara_detector', 'npm_bin_detector'])
Per-severity list of the unique files detected at each level (a level string or a list of them; high/medium/low/other):
# Single level (string)
d.print_report_by_severity('high')
# Several levels (list of strings)
d.print_report_by_severity(['high', 'medium'])
Restricting & Selecting Plugins
The analyzer pipeline can be narrowed per assessment. only_* arguments act as
an allowlist (applied first); ignore_* arguments act as a blocklist
(subtracted after). All four accept a list and can be combined.
Categories: plugins_version_extractors, plugins_classifiers,
plugins_static, plugins_deep, plugins_judgements, plugins_reporting.
Restrict individual plugins (skip by name):
d.assess_package('lodash', ignore_plugins=['claude_deobfuscator'])
Restrict plugin categories (skip by category):
d.assess_package('lodash', ignore_plugin_category=['plugins_deep'])
Run only individual plugins (allowlist by name):
d.assess_package('lodash', only_plugins=['yara_detector', 'indicator_match'])
Run only individual plugin categories (allowlist by category):
d.assess_package('lodash', only_plugin_category=['plugins_static'])
Output Directory
Default output schema:
cache/
└── lodash-npm-1781637646/
├── downloads/ #:: Downloaded package artifacts
│ └── lodash-4.17.21.tgz
├── extracted/ #:: Decompressed package contents
│ └── package/
│ ├── index.js
│ ├── lodash.js
│ └── ...
├── cached_artifacts/ #:: Cached plugin analysis artifacts
│ ├── cached_artifact_lodash-npm-1781637646_1781720055_claude_deobfuscator.txt
│ └── extracted_iocs.json
├── cached_directory/ #:: Cached registry metadata JSON
│ └── CACHED_DIRECTORY_lodash-npm-1781637646.dat
├── session_report/ #:: Session report JSON output
│ └── lodash-npm-1781637646.json
└── other/ #:: General-purpose scratch space
Custom output location:
# At construction
d = solorider.SupplyChainDetector(output_dir='/home/user/scans')
d.assess_package('lodash')
# At invocation (overrides construction)
d = solorider.SupplyChainDetector()
d.assess_package('lodash', output_dir='/home/user/scans')
d.assess_dependencies('requirements.txt', output_dir='/home/user/deps_scan')
Architecture
solorider uses a plugin model dispatched across several layers. When a package name is received for assessment, it is broadcast across ecosystem plugins to determine presence. After identification, the package is extracted to disk and analyzed across analyzer plugins in categorical order.
┌──────────────────┐ ┌──────────────────┐ ┌────────────────────┐ ┌──────────────────┐
│ Input │ │ Scoping │ │ Analyzers │ │ Reporting │
│ │ │ │ │ │ │ │
│ │ │ ╭────────────╮ │ │ ╭──────────────╮ │ │ │
│ │ │ │ npm │ │ │ │ Classifiers │ │ │ │
│ │ │ ╰─────┬──────╯ │ │ ╰──────┬───────╯ │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ ▼ │ │ ▼ │ │ │
│ │ │ ╭────────────╮ │ │ ╭──────────────╮ │ │ ╭────────────╮ │
│ ╭──────────────╮ │ │ │ pypi │ │ │ │ Static │ │ │ │ JSON │ │
│ │assess_package│ │ │ ╰─────┬──────╯ │ │ │ detection │ │ │ ╰─────┬──────╯ │
│ │ assess_deps │─┼──►│ │ │──►│ ╰──────┬───────╯ │──►│ │ │
│ ╰──────────────╯ │ │ ▼ │ │ ▼ │ │ ▼ │
│ │ │ ╭────────────╮ │ │ ╭──────────────╮ │ │ ╭────────────╮ │
│ │ │ │ aur │ │ │ │ Deep │ │ │ │ Python │ │
│ │ │ ╰─────┬──────╯ │ │ │ detection │ │ │ ╰────────────╯ │
│ │ │ │ │ │ ╰──────┬───────╯ │ │ │
│ │ │ ▼ │ │ ▼ │ │ │
│ │ │ ╭────────────╮ │ │ ╭──────────────╮ │ │ │
│ │ │ │ github │ │ │ │ Judgements │ │ │ │
│ │ │ ╰────────────╯ │ │ ╰──────────────╯ │ │ │
│ │ │ │ │ │ │ │
└──────────────────┘ └──────────────────┘ └────────────────────┘ └──────────────────┘
Accessing Results Programmatically
import solorider
d = solorider.SupplyChainDetector()
d.assess_package('yay')
# Ecosystem results
d.DOWNLOADER.FOUND # True
d.DOWNLOADER.PACKAGE_PRESENCE # {'aur': False, 'npm': True, 'pypi': True, ...}
d.DOWNLOADER.PRESENT_PACKAGES # ['npm', 'pypi']
# Iterate child assessments
for child in d.ASSESSMENT_OBJECTS:
child.TMP_MODE # 'npm'
child.SESSION_NAME # 'yay-npm-1781719850'
child.HAS_DETECTIONS # True
child.REPORT['type'] # 'npm'
child.REPORT['package_url'] # 'https://registry.npmjs.org/...'
child.REPORT['metadata'] # [{'key': 'name', 'value': 'yay'}, ...]
# Files
for f in child.REPORT['files']:
f['path'] # 'package/index.js'
f['size'] # 283
f['md5'] # 'a1b2c3d4...'
f['sha1'] # 'da39a3ee...'
f['sha256'] # 'edb172e0...'
# Detections per file
for f in child.REPORT['files']:
f['detections_plugins_classifiers']
f['detections_plugins_static']
f['detections_plugins_deep']
f['plugins_extracted_artifacts']
# Collect all detections
all_detections = []
for f in child.REPORT['files']:
for key in ('detections_plugins_classifiers',
'detections_plugins_static',
'detections_plugins_deep'):
all_detections.extend(f.get(key, []))
# Filter
high_severity = [d for d in all_detections if d['severity'] == 'high']
yara_hits = [d for d in all_detections if d['plugin_name'] == 'yara_detector']
# Judgements
is_malicious = any(j['malicious'] for j in child.REPORT['judgements'])
# Print reports
d.print_reports()
# Export as JSON
import json
for child in d.ASSESSMENT_OBJECTS:
with open(f"{child.SESSION_NAME}.json", "w") as f:
json.dump(child.REPORT, f, indent=2, default=str)
Designing & Deploying Plugins
Plugin architecture is implemented for both polling code repositories and assessing files within retrieved packages. Plugins can be developed and deployed by dropping files into the appropriate directory.
Dependency plugins expand retrieval capabilities across code repositories. When a package is polled, solorider broadcasts the package name to each plugin to determine ecosystem presence.
Analysis plugins expand detection capabilities. When analysis occurs, a JSON object containing all file metadata is broadcast to each plugin in a specific order.
Order of operations:
1. Classifiers -- extend metadata or derive light characteristics
2. Static -- determinations based on static features (bytes)
3. Deep -- deeper analysis (deobfuscation, LLM, etc)
4. Judgements -- render decisions based on security policy
5. Reporting -- output to STDOUT, REST API, secondary systems
Plugin functions:
add_detection() -- add a detection to a file record
add_artifact() -- attach an extracted artifact to a file record
cache_artifact() -- export data to the session output directory
add_judgement() -- add a malicious/benign judgement
add_report() -- add a verbose report
Usage:
self.add_detection(record=record, detection="empty_file", message="File is 0 bytes", severity="low")
self.add_artifact(record=record, artifact={"indicator": "185.231.68.0", "type": "c2_ip"})
self.cache_artifact(data=open(target_path, "rb").read(), file_name="extracted_payload.bin")
self.add_judgement(malicious=True, message="3 files matched known malware indicators")
self.add_report(report_name="threat summary", report="[!] Package contains credential stealer")
Example analysis plugin:
from solorider.plugin_base import PluginBase
class MyDetector(PluginBase):
name = "my_detector"
def __init__(self):
self.NAME = "my_detector"
self.DESCRIPTION = "Detects something suspicious."
def run(self, context):
for record in context["report"]["files"]:
if record.get("size", 0) == 0:
self.add_detection(
record=record,
detection="empty_file",
message="File is 0 bytes",
severity="low",
)
Example ecosystem plugin:
from solorider.lib.downloader_plugin_base import DownloaderPluginBase
class RubyGemsChecker(DownloaderPluginBase):
PLUGIN_NAME = "rubygems_checker"
TYPE = "rubygems"
BASE_REPO_URL = "https://rubygems.org"
def accepts(self, raw_input):
...
def check(self):
...
def download(self, download_directory):
...
Drop either into the appropriate plugin directory. Live on the next run.
Innovation Guidance
Current LLMs do a fantastic job of interpreting solorider's architecture and are a great way to streamline expansion of the framework and complement capabilities of existing AI-based tooling (agents, MCP servers, etc).
Users of solorider are encouraged to upload it to your favorite LLM (such as Claude) and iterate on new signatures and plugins for the framework.
While solorider is effectively a proof-of-concept, its orchestration framework is robust enough to be a starting point for a tailored solution to scaling detection of backdoored repositories.
Report Schema
The following JSON object is contained as a static property within the SupplyChainDetector class (.REPORT) and is exposed to plugins via context['report'].
{
"session_name": "lodash-npm-1781637646",
"package_url": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"date": "2026-06-17 02:40:32.451289+00:00",
"date_epoch": 1781637632,
"metadata": [
{"key": "name", "value": "lodash"},
{"key": "version", "value": "4.17.21"},
{"key": "description", "value": "Lodash modular utilities."}
],
"type": "npm",
"extracted_package_name": "lodash",
"extracted_package_version": "4.17.21",
"extracted_pinned_version_str": "lodash@4.17.21",
"stated_pinned_version": "",
"files": [
{
"path": "package/dist/lodash.core.js",
"size": 2148903,
"md5": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
"sha1": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
"sha256": "edb172e0c2c9bc0f89eb4e291526593cf68d6020fc8cf6c8a5392e771f448635",
"detections_plugins_classifiers": [
{
"plugin_name": "anomalous_size",
"detection": "anomalous_file_size",
"message": "File is 2,148,903 bytes, 1247% above average",
"severity": "medium"
}
],
"detections_plugins_static": [
{
"plugin_name": "yara_detector",
"detection": "general_ObfuscatorPattern",
"message": "Determines if uses obfuscation",
"severity": "high"
},
{
"plugin_name": "indicator_match",
"detection": "matched_sha256",
"message": "SHA256 matches known indicator: edb172e0...",
"severity": "high"
}
],
"detections_plugins_deep": [
{
"plugin_name": "claude_deobfuscator",
"detection": "claude_behavioral_analysis",
"message": "Harvests GitHub authentication tokens",
"severity": "high"
}
]
}
],
"judgements": [
{
"judgement_name": "standard_judgement",
"malicious": true,
"message": "There were multiple detections on this package which may need to be reviewed"
}
],
"reports": [
{
"plugin_name": "standard_report",
"report_name": "solorider default summary",
"report": "[!] - This package had detections that may need review ..."
}
]
}
License
solorider is released under the MIT License and is free and open source. The software is provided "as is", without warranties or guarantees of any kind, and its authors accept no liability for its use. Use at your own risk.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file solorider-1.0.3.tar.gz.
File metadata
- Download URL: solorider-1.0.3.tar.gz
- Upload date:
- Size: 105.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3651ff5de13b69a5c16bc47a907990fdc22e1c835ad9040ec8186ddc232d9014
|
|
| MD5 |
a3dbf8181a9c8d3db8df75df9eb3f690
|
|
| BLAKE2b-256 |
dcb23d136f59a0ecc52294cb7e0c41dce8b3e77f950fa4ac758cf78909f638e8
|
Provenance
The following attestation bundles were made for solorider-1.0.3.tar.gz:
Publisher:
publish.yml on matonis/solorider
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
solorider-1.0.3.tar.gz -
Subject digest:
3651ff5de13b69a5c16bc47a907990fdc22e1c835ad9040ec8186ddc232d9014 - Sigstore transparency entry: 1998977884
- Sigstore integration time:
-
Permalink:
matonis/solorider@58051abd94e0d75197b885c026a5e2487993f718 -
Branch / Tag:
refs/tags/v1.0.3 - Owner: https://github.com/matonis
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@58051abd94e0d75197b885c026a5e2487993f718 -
Trigger Event:
push
-
Statement type:
File details
Details for the file solorider-1.0.3-py3-none-any.whl.
File metadata
- Download URL: solorider-1.0.3-py3-none-any.whl
- Upload date:
- Size: 141.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
728e6333951c352bff8a92d61fdb9daca34916438798c4b617f587b6a08dd0ca
|
|
| MD5 |
d9e5300825929b613de6d731532f1d6a
|
|
| BLAKE2b-256 |
9de59e9230f8ef2e1fdaf2b19dfeee7d0033c88a4492ce9cc942dcfb9af05d4a
|
Provenance
The following attestation bundles were made for solorider-1.0.3-py3-none-any.whl:
Publisher:
publish.yml on matonis/solorider
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
solorider-1.0.3-py3-none-any.whl -
Subject digest:
728e6333951c352bff8a92d61fdb9daca34916438798c4b617f587b6a08dd0ca - Sigstore transparency entry: 1998977992
- Sigstore integration time:
-
Permalink:
matonis/solorider@58051abd94e0d75197b885c026a5e2487993f718 -
Branch / Tag:
refs/tags/v1.0.3 - Owner: https://github.com/matonis
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@58051abd94e0d75197b885c026a5e2487993f718 -
Trigger Event:
push
-
Statement type: