Structural-honesty checks for Python, powered by Furqan
Project description
furqan-lint
Structural-honesty checks for Python, powered by Furqan.
furqan-lint translates Python source into the Furqan AST and runs the
subset of Furqan checkers whose semantics carry across language boundaries
into idiomatic Python. Four checks ship today:
- D24 (all-paths-return) every control-flow path through a typed function reaches a return statement.
- D11 (status-coverage) when a function returns
Optional[X], every caller either propagates the optionality or explicitly handlesNone. A caller that silently collapsesOptional[X]into a non-optional return type is the structural equivalent of dropping theIncompletearm of Furqan'sIntegrity | Incompleteunion. - return_none_mismatch a function declaring
-> str(or any non-Optional type) that returnsNoneon some path is flagged as a type mismatch. Closes the D24 return-None blind spot. - additive_only invoked via
furqan-lint diff old.py new.py, compares two versions of a module's public surface and fires on any removed name. Adding a public name is silent.
Install
pip install furqan-lint
This installs the latest release from PyPI. Requires Python 3.10+ and furqan>=0.11.0.
Optional adapters
pip install "furqan-lint[rust]" # tree-sitter Rust adapter
pip install "furqan-lint[go]" # Go adapter (requires Go 1.22+ toolchain at install time)
pip install "furqan-lint[onnx]" # ONNX adapter (D24-onnx + opset-compliance)
pip install "furqan-lint[rust,go,onnx]" # all three adapters
Install from a specific commit or tag
pip install "git+https://github.com/BayyinahEnterprise/furqan-lint.git@v0.8.4"
Replace v0.8.4 with any tag from the release history or main for the development tip.
Furqan dependency
furqan-lint requires furqan>=0.11.0, the Furqan programming-language tooling. As of 2026-05-03 the PyPI release of furqan is at v0.10.1; install v0.11.1 directly from GitHub:
pip install "git+https://github.com/BayyinahEnterprise/furqan-programming-language.git@v0.11.1"
This GitHub-pin step will not be necessary once furqan v0.11.1 is published to PyPI.
Rust support (opt-in)
As of v0.7.0, furqan-lint can lint .rs files. Rust support is
behind an opt-in extra so the Python-only install path is unchanged:
pip install "furqan-lint[rust]"
This pulls in tree-sitter and tree-sitter-rust (PyPI ships
ARM64 and x86_64 wheels for both; no source build required).
As of v0.7.2, .rs files run three checkers: R3 (ring-close,
zero-return on annotated functions, via upstream
furqan.checker.check_ring_close), D24 (all-paths-return), and
D11 (status-coverage). The D11 producer predicate recognises
both Option<T> and Result<T, E> returns; a caller that calls
a may-fail helper without propagating the union is flagged.
The planned analogue of return_none_mismatch was dropped per
the v0.7.2 prompt-grounding self-check, which empirically
demonstrated that the firing condition is unreachable on any
compilable Rust source (rustc rejects fn f() -> i32 { None }
at compile time before furqan-lint sees the file). Trait objects,
lifetimes, macro expansion, closure return-type checks, and
Cargo workspace traversal remain out of scope.
Edition is read from the nearest ancestor Cargo.toml's
[package].edition field (one of "2018", "2021", "2024"); if
no Cargo.toml is found or the field is malformed, edition
defaults to "2021". The current implementation does not branch on edition.
Go support (opt-in)
As of v0.8.1, furqan-lint can lint .go files (Go diff in v0.8.1; goast emits qualified method names as of v0.8.2). Go support is
behind an opt-in extra so the Python-only install path is unchanged:
pip install "furqan-lint[go]"
The Go toolchain (1.21+) is required at install time so the
PEP 517 build hook can compile the bundled goast binary; it
is not required at runtime.
As of v0.8.1, .go files run two checkers: D24 (all-paths-
return) and D11 (status-coverage with the (T, error) firing
shape). The cross-language _is_may_fail_producer predicate
(Shape B) recognizes the (T, error) return convention; a
caller that calls a may-fail helper without propagating the
union is flagged. R3 (zero-return) is documented not-applicable
to Go: the Go compiler rejects all firing shapes at compile
time.
Additive-only diff is supported for .go files: furqan-lint diff old.go new.go extracts uppercase-initial public names
from each file via goast and reports any names that were
present in old but not in new. The diagnostic prose is
language-aware: Go users see var Name = <new> re-export hints
rather than Python alias syntax. Cross-language diffs (e.g.
foo.py vs bar.go) return exit 2 with a "Cross-language
diff not supported" message.
ONNX support (opt-in)
As of v0.9.0, furqan-lint can lint .onnx model files. ONNX
support is behind an opt-in extra so the Python-only install
path is unchanged:
pip install "furqan-lint[onnx]"
This pulls in onnx>=1.14,<1.19. The upper bound is load-bearing:
the ONNX op registry retroactively adds operators across onnx
package releases, so an unpinned upper bound would silently
change what counts as e.g. opset 11. No onnxruntime dependency:
lint-time checks operate on the graph structure, not on inference.
.onnx files run three structural checks (current as of v0.9.1):
- D24-onnx (all-paths-emit). Every declared output in
graph.outputmust be reachable from some node in the graph (or be a graph input passed through). The structural shape mirrors a function with a missing return statement. - opset-compliance. Every node's
op_typemust exist in the declared opset, looked up viaonnx.defs.get_schema(..., max_inclusive_version=opset_version)against the pinnedonnx>=1.14,<1.19registry. - D11-onnx (shape-coverage, v0.9.1). Run
onnx.shape_inference.infer_shapes(model_proto, strict_mode=True); if it raisesInferenceError, parse the per-op message and emit oneshape_coveragediagnostic per offender. Strict-mode silent-passes ondim_param(symbolic) and emptydim_value(dynamic) shapes; this is documented as thedynamic_shape_silent_passfour-place limit.
ONNX is structurally a different substrate from Python / Rust /
Go source code. Nodes are not functions; edges are not return
statements; ValueInfo is not a type signature. The ONNX adapter
ships a parallel diagnostic family inspired by the Furqan
structural-honesty primitives, not new instances of the existing
check_d24 / check_status_coverage checkers operating on a
unified IR. The diagnostic spirit is shared (surface claims must
match substrate dataflow); the implementation is its own
package with its own runner.
The additive-only diff covers graph.input and graph.output
ValueInfo entries only. graph.value_info (intermediate tensors)
and graph.initializer (parameter tensors) are explicitly out
of scope; including them would create false positives on every
model retraining.
Usage
furqan-lint check path/to/file.py
furqan-lint check path/to/directory/
furqan-lint diff old_version.py new_version.py
furqan-lint version
CI Integration
Two ways to wire furqan-lint into your workflow.
GitHub Action
Three lines in your workflow file run the structural checks on every push or pull request:
# .github/workflows/furqan-lint.yml
name: Furqan Lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: BayyinahEnterprise/furqan-lint@v0.4.0
with:
path: src/
Inputs (all optional):
path-- file or directory to check. Default:.python-version-- Python version to use. Default:3.12furqan-lint-version-- pinned version to install. Default: install latest frommain.
Pre-Commit Hook
Run the same checks locally on every git commit against staged
Python files:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/BayyinahEnterprise/furqan-lint
rev: v0.4.0
hooks:
- id: furqan-lint
Then pre-commit install. Failures block the commit.
Using with Other Tools
furqan-lint is complementary to ruff and mypy. Each catches a different class of issue:
| Tool | Catches | Overlap with furqan-lint |
|---|---|---|
| ruff | Style, unused imports, complexity, common bug patterns, formatting (replaces black + isort + flake8 + pyupgrade) | None |
| mypy | Type errors, some missing returns | Partial overlap on D24 and return-none. mypy does NOT catch Optional collapse (D11) or API-breaking changes (additive-only). |
| furqan-lint | Missing return paths, Optional collapse, return-None mismatch, API-breaking changes, zero-return functions | See mypy column |
Recommended .pre-commit-config.yaml for Your Project
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.0
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.13.0
hooks:
- id: mypy
- repo: https://github.com/BayyinahEnterprise/furqan-lint
rev: v0.5.0
hooks:
- id: furqan-lint
Then pre-commit install. Run order: ruff (lint + format) -> mypy
(types) -> furqan-lint (structural honesty). Each layer catches what
the previous layers do not.
Contributing to furqan-lint
git clone https://github.com/BayyinahEnterprise/furqan-lint.git
cd furqan-lint
pip install -e ".[dev]"
pre-commit install
# Run all tools manually
ruff check .
ruff format --check .
mypy
pytest -q
# Run by test category
pytest -m unit # fast, in-process, no subprocess
pytest -m integration # CLI and pipeline tests
pytest -m "not slow" # skip slow tests
pytest -m "not network" # skip network-dependent tests
The furqan-lint check src/ self-check runs as part of pre-commit;
the tool that catches drift in other people's code must not have
drift in its own.
Example
# example.py
from typing import Optional
def find_record(id: int) -> Optional[dict]:
if id <= 0:
return None
return {"id": id}
def get_name(id: int) -> str:
record = find_record(id)
if record is not None:
return record["name"]
# Missing else: falls through with no return
$ furqan-lint check example.py
MARAD example.py
3 violation(s):
[all_paths_return] Function 'get_name' at line 8 declares
-> str but not every control-flow path reaches a return
statement.
[status_coverage] Function 'get_name' at line 8 calls
'find_record' (returns Optional[dict]) but declares -> str.
The Optional is silently collapsed.
[return_none_mismatch] Function 'get_name' at line 8
declares -> str but returns None on at least one path.
Closed in v0.4.1
- D11 monkey-patch retired. The producer-predicate hack went
through three lifecycle stages: a stopgap monkey-patch in v0.1.0
on
status_coverage._is_integrity_incomplete_union, a scoped context manager in v0.3.0, and athreading.Lockfor safety in v0.3.0. v0.4.1 retires the patch entirely by passing the Python-Optional predicate via the upstreamproducer_predicate=keyword oncheck_status_coverage, available sincefurqan>=0.11.0. Closes the full lifecycle of a round-1 audit finding. - Pre-commit hook installability. The hook now declares
furqanas anadditional_dependencyvia git URL, sopre-commit installcan resolve the dependency that PyPI does not yet host.
Closed in v0.3.5
Two corrective fixes promoting documented limitations to fixes:
- Exception-driven fall-through.
try/exceptbodies are now modelled as maybe-runs (the success path =try.body + orelsebecomes the body of a syntheticIfStmt; handlers chain into theelse_body). D24 now correctly flags the false-negative case where a function's only return path is inside atryblock whose except handler falls through (the canonical mypy "Missing return statement" shape). Documented as a known limit since v0.3.1. - PEP 604
None | None. Now translates to bareTypePath("None"), the same shapeOptional[None](v0.3.4) andUnion[None](v0.3.3) produce. All three optional-spelling paths are now structurally identical for the all-None case. Documented as a v0.4.0 candidate in v0.3.4.
Closed in v0.3.2
Three findings from a round-5 review of v0.3.1, all reproduced empirically and fixed:
Union[X, None]recognition.Union[X, None],Union[None, X],Union[X, Y, None], and thetyping.Union/t.Unionaliased forms are now treated as Optional. Older codebases (pre-PEP 604) routinely useUnion[X, None]and were producing false-positivereturn_none_mismatchdiagnostics.- String forward-reference annotations. PEP 484 string
annotations like
-> "Optional[User]"(the canonicalTYPE_CHECKINGidiom for breaking circular imports) are now parsed and recursed into. Pre-v0.3.2 the literal string was treated as a bare type name. - Nested class methods. Methods of
Outer.Inner.method,Outer.Mid.Inner.method, etc. are now collected via recursive descent through nestedClassDefbodies. Pre-v0.3.2 the descent stopped at one level and inner-class methods were silently dropped, producing false-negative D24 andreturn_none_mismatchon a common Python idiom.
Closed in v0.3.0
Six findings from a three-round review of v0.2.0, all reproduced empirically and fixed:
- Compound-statement blind spot.
for,while,with,try, andmatchbodies are now translated, soreturn Noneinside any of them is caught byreturn_none_mismatch. Loop andexceptbodies wrap as maybe-runs ifs so D24 doesn't over-claim coverage. - Additive surface gaps.
MAX_RETRIES: int = 5andA, B = 1, 2are now visible to the additive checker. Annotated__all__declarations are also read. - Dynamic
__all__cascade. A non-static__all__now raisesDynamicAllErrorand the CLI exits 2 with anINDETERMINATEresult, rather than silently treating the surface as empty. - D11 thread-safety. A
threading.Lockserialises concurrent entry to the monkey-patched-predicate context manager. Optionalover-match.weird.lib.Optional[X]is no longer treated astyping.Optional[X].int | strrendering. Diagnostic prose for non-Optional unions no longer saysOptional[Unknown].
Closed in v0.2.0
- D24 return-None blind spot. A function declaring a non-Optional
return type that returns
Noneis now caught by thereturn_none_mismatchchecker. - Nested-function call attribution. Calls inside closures, inner functions, and methods of inner classes are no longer attributed to the enclosing function.
- Decorator call attribution. Decorators are no longer collected as calls inside the decorated function's body.
Remaining limitations
Each limitation here has a fixture in tests/fixtures/documented_limits/
and a test in tests/test_documented_limits.py pinning the current
behaviour, so any change (in either direction) is intentional rather
than silent.
self.method()calls. The adapter resolvesself.foo()to the bare method namefoo, the same as a plainfoo()call. This is not a bug today but will need revisiting if the adapter ever stores qualified call paths.- Checker coverage. Only four of Furqan's ten checkers run on Python. The rest depend on Python-specific conventions (scope declarations, layer annotations, calibration bounds, dependency mapping) that standard Python does not provide.
- Return-type expression inference.
return_none_mismatchonly catches theNoneliteral. A-> intfunction returning"hello"is not caught. - Exhaustive
matchrecognition. Each case body wraps as a maybe-runsIfStmt, so D24 cannot recognise a structurally exhaustivematch(with acase _:arm) as guaranteed coverage. Future work could splice the catch-all case into the priorIfStmt'selse_body. - Aliased
Optional/Unionimports.from typing import Optional as MyOpt; -> MyOpt[X]is treated as a non-Optional return type. The same gap applies toUnion:from typing import Union as U; -> U[X, None]andfrom somelib import Union; -> Union[X, None]both bypass the bare-name andtyping./t.matchers. The matcher recognises the bareOptional/Unionnames and the qualifiedtyping./t.forms only; arbitrary aliases and same-named imports from non-typingmodules need symbol-table tracking (parse imports, build alias map, resolve before matching), which is deferred to a future phase. Workaround: use the bare or qualified form, or rename the import toimport typing as t. - Local classes inside any function or method body. A class
defined inside a function body or a method body has its methods
silently dropped. The v0.3.2 nested-class fix added recursive
descent through top-level
ClassDef->ClassDef(soOuter.Inner.methodis collected); it does NOT extend throughFunctionDef->ClassDefregardless of whether theFunctionDefis at module scope or inside anotherClassDef. The argument for the asymmetry: a local class is a private implementation detail (often a closure-like return value), not part of the module's public contract that D24 andreturn_none_mismatchexist to enforce. If a real-world regression demonstrates otherwise, extend the function walker to descend into localClassDefbodies and call_collect_class_methods.
Rust adapter (current as of v0.8.3)
Each Rust limit has a fixture in
tests/fixtures/rust/documented_limits/ and a pinning test in
tests/test_rust_correctness.py.
- Trait-object return types. Functions returning
Box<dyn Trait>are translated to aTypePaththat ignores the trait-object payload. Trait-object polymorphism is out of scope; a future a future checker would be the right place to revisit. Pinned astests/fixtures/rust/documented_limits/trait_object_return.rs. - Lifetime-affected return types. Functions with explicit
lifetime parameters (
fn f<'a>(...) -> &'a str) have their lifetimes stripped during translation; the return type is treated as-> &'a strliterally (no lifetime semantics). D24's path-coverage logic is unaffected; a future borrow-pattern checker would need lifetime preservation. Pinned astests/fixtures/rust/documented_limits/lifetime_param_return.rs. - Closures with annotated return types.
closure_expressionnodes are skipped for D24, D11, AND R3 in v0.7.1. The outer function is checked normally; the closure body is opaque. A future phase may revisit when there is a concrete user-reported false negative. Pinned astests/fixtures/rust/documented_limits/closure_with_annotated_return.rs. extract_public_namesomits impl-block methods. The Rust additive-only diff path's name extractor walks only top-level CST root children; methods defined insideimpl Type { ... }blocks are intentionally not collected in v0.8.3. Asymmetric with goast (which emits qualified method names likeCounter.incrementas of v0.8.2). Pinned astests/fixtures/rust/documented_limits/impl_methods_omitted.rs(added in v0.8.3). Resolution path: registered as a v0.8.4 candidate.panic!()(or any diverging macro) used as a tail expression with no;. The translator synthesizes aReturnStmt(opaque)for any tail expression per the v0.7.0 R1 rule, so R3 (zero-return) does not fire onfn f() -> i32 { panic!() }. Adding a fix would require either a hardcoded diverging-macro allowlist (brittle) or cross-file type inference of the macro's expansion type (out of scope). A future phase may revisit if the Rust ecosystem standardizes a#[diverging]attribute. Pinned astests/fixtures/rust/documented_limits/r3_panic_as_tail_expression.rs.
Go adapter (current as of v0.8.2)
Each Go limit has a fixture in
tests/fixtures/go/documented_limits/ and a pinning test in
tests/test_go_documented_limits.py (or, for the older
translator-level limits, in tests/test_go_translator.py).
- 3+-element return signatures. Translate to opaque
TypePath("<multi-return>"). D24 and D11 see the function but cannot reason about the individual arms. Pinned astests/fixtures/go/documented_limits/multi_return_three_or_more.go. - 2-element non-error tuple returns. Translate to opaque
TypePath("(T, U)"). D11's may-fail predicate does NOT fire on these; only(T, error)shapes are recognized as may-fail per locked decision 4. Pinned astests/fixtures/go/documented_limits/two_element_non_error_tuple.go. forandfor-rangebodies. Wrap as may-runs-0-or-N opaque IfStmt. D24 cannot prove that aforbody that always returns guarantees coverage. Pinned astests/fixtures/go/documented_limits/for_statement_opaque.go.switchbodies. Wrap as may-runs-0-or-N opaque IfStmt; case-arm returns are invisible to D24. Pinned astests/fixtures/go/documented_limits/switch_statement_opaque.go.selectbodies. Wrap as may-runs-0-or-N opaque IfStmt. Pinned astests/fixtures/go/documented_limits/select_statement_opaque.go.deferstatements. Wrap as opaque; the deferred call's effect on control flow (panic recovery, resource cleanup) is not modeled. Pinned astests/fixtures/go/documented_limits/defer_statement_opaque.go.- Interface method dispatch. Calls through interface
receivers are not specially modeled; the receiver type is
opaque to the adapter. Pinned as
tests/fixtures/go/documented_limits/interface_method_dispatch.go. - Generic type parameters. Syntactically allowed in
signatures but their constraints are ignored. Pinned as
tests/fixtures/go/documented_limits/generic_type_parameters.go. - R3 not-applicable. The Go compiler rejects all R3 firing
shapes (zero-return on annotated functions) at compile time;
the only compilable nearest-edge case is a named-return with
bare
return, which the translator sees as having a return statement. Pinned astests/fixtures/go/documented_limits/r3_compile_rejected.go(added in v0.8.1).
ONNX adapter (current as of v0.9.1)
Each ONNX limit has a fixture in
tests/fixtures/onnx/documented_limits/ and a pinning test in
tests/test_onnx_correctness.py,
tests/test_onnx_public_surface_additive.py, or
tests/test_onnx_shape_coverage.py.
- Dynamic shape silent-pass. Strict-mode shape inference
silent-passes on
dim_param(symbolic batch / sequence dims like"batch") and emptydim_value(dynamic shapes). v0.9.1 takes the position that this is the right default because ONNX models withdim_paramare typically deployment-time signature shapes that bind concrete values at runtime; a future release may revisit if a concrete user-reported false negative motivates a stricter mode. Pinned astests/fixtures/onnx/documented_limits/dynamic_shape_silent_pass.py. graph.value_infoandgraph.initializernot in additive contract. The additive-only diff (furqan-lint diff old.onnx new.onnx) coversgraph.inputandgraph.outputValueInfo only. Intermediate tensors and initializers are out of scope per Decision 5 of the v0.9.0 prompt; including them would create false positives on every model retraining. Pinned astests/fixtures/onnx/documented_limits/intermediates_excluded.py.- ONNX op-registry pin window
>=1.14,<1.19. Op registry version is pinned to prevent silent semantics drift acrossonnxpackage upgrades (the ONNX op registry retroactively adds operators across releases). Consumers requiring a newer registry must wait for a furqan-lint patch release that bumps the pin. Pinned astests/fixtures/onnx/documented_limits/registry_pin_window.py.
Retired in v0.9.1
- D11-onnx deferred to v0.9.1 (former
shape_coverage_deferreddocumented limit). v0.9.1 ships D11-onnx via strict-mode shape inference, so the deferral entry is no longer load-bearing. The companion v0.9.0 pinning testtest_onnx_d11_deferred_v0_9_0_passesis also deleted in v0.9.1 commit 4 per the delete-plus-add discipline (round-30 MED-1 closure). The v0.9.1 firing testtest_d11_onnx_fires_on_shape_mismatchreplaces it.
License
Apache-2.0.
Project details
Release history Release notifications | RSS feed
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 furqan_lint-0.9.1.tar.gz.
File metadata
- Download URL: furqan_lint-0.9.1.tar.gz
- Upload date:
- Size: 172.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a507be602224fa086f9444b5d28c9f6734a2c93913d3b61e0b2fb291add82105
|
|
| MD5 |
e7e0d79bf9afb4f4ccfce57550a0b188
|
|
| BLAKE2b-256 |
8d463560389e5b2855616ea5bc4556f93f857e884ad9ebb208269b58fb1f2e60
|
Provenance
The following attestation bundles were made for furqan_lint-0.9.1.tar.gz:
Publisher:
release.yml on BayyinahEnterprise/furqan-lint
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
furqan_lint-0.9.1.tar.gz -
Subject digest:
a507be602224fa086f9444b5d28c9f6734a2c93913d3b61e0b2fb291add82105 - Sigstore transparency entry: 1437886312
- Sigstore integration time:
-
Permalink:
BayyinahEnterprise/furqan-lint@baf00597ee3eacab130cf469503432cc482cdf3f -
Branch / Tag:
refs/tags/v0.9.1 - Owner: https://github.com/BayyinahEnterprise
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@baf00597ee3eacab130cf469503432cc482cdf3f -
Trigger Event:
push
-
Statement type:
File details
Details for the file furqan_lint-0.9.1-py3-none-any.whl.
File metadata
- Download URL: furqan_lint-0.9.1-py3-none-any.whl
- Upload date:
- Size: 2.0 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1ece0da38d87acee2742555b42ebcae9b1634ff0eb66c4f65c69c7048817b4ec
|
|
| MD5 |
227bdde932cb6f736170a1aac3d5433d
|
|
| BLAKE2b-256 |
ad2346808bf88e43fa42d2cf73994fc3b5fd28ff060a53696bcc3e14322ba785
|
Provenance
The following attestation bundles were made for furqan_lint-0.9.1-py3-none-any.whl:
Publisher:
release.yml on BayyinahEnterprise/furqan-lint
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
furqan_lint-0.9.1-py3-none-any.whl -
Subject digest:
1ece0da38d87acee2742555b42ebcae9b1634ff0eb66c4f65c69c7048817b4ec - Sigstore transparency entry: 1437886326
- Sigstore integration time:
-
Permalink:
BayyinahEnterprise/furqan-lint@baf00597ee3eacab130cf469503432cc482cdf3f -
Branch / Tag:
refs/tags/v0.9.1 - Owner: https://github.com/BayyinahEnterprise
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@baf00597ee3eacab130cf469503432cc482cdf3f -
Trigger Event:
push
-
Statement type: