Releases: Signetry/core
Releases · Signetry/core
Release list
signetry-core v0.8.0
Added — the receipt format is now a published, independently testable spec
docs/RECEIPT_SPEC.mddocuments the
signetry.remediation-receiptv1 format in full: envelope, payload,
canonicalization, signing, the verification algorithm, the §4.3 invariants, and a
change contract. RFC 2119 language throughout. A receipt is meant to be verifiable
by someone who does not have this tool and is reading it years later, so the format
is an interface and is now written down as one.tests/conformance/— 17 assertions over 7 committed JSON
vectors, with published test-key seed strings so an implementation in any language
can be checked against exactly the same files. Regenerate with
python tests/conformance/generate_vectors.py; the vectors are committed rather
than computed at test time so a change to canonicalization or signing shows up as a
diff.- The spec and the suite are Apache-2.0, named as explicit
exclusions from the BUSLLicensed WorkinLICENSE. They carry no
restriction and no Change Date. Writing a competing issuer or an independent
verifier against the spec is a supported use. check_invariants(receipt)(exported fromsignetry_core.pipeline) enforces
RECEIPT_SPEC §4.3:auto_mergemust befalse,human_review_requiredmust be
true, pluskind/version/authority_levelwell-formedness.verify_receipt
now returnsconformingandinvariant_violationsalongside its cryptographic
result, because those are different questions — a receipt can be correctly signed
and still claim something the format forbids.signetry verifynow fails on a non-conforming receipt, not just an unverifiable
one, and says which of the two failed. A validly signed receipt with
auto_merge: trueprintsNON-CONFORMINGandREJECTEDand exits1; it never
prints a bareVERIFIED. This is what makes "Signetry never merges on its own
judgement" a checkable property of every receipt instead of a promise in a README.
Added — policy registry
signetry policiesandsignetry init --policy <id>. Six starter admission
contracts for common repository shapes:docs-only,dependency-bump,
python-library,node-service,monorepo-service,ci-workflow-fix. Writing the
first contract is where adoption stalls, and "which globs should an agent be allowed to
touch in this stack" is a real security decision most teams defer.- The published file is the installed file.
init --policycopies the registry bytes
verbatim — no templating, no merge — so an adopter can diff their
.signetry/admission.yamlagainst the registry and get nothing back. Verified in CI. - Every entry carries its own evidence. A policy declares example paths it must block and
must allow in# @policyheader comments, andtests/test_policy_registry.pyruns each
claim through the realevaluate_contract. A policy whose documentation does not match
its behaviour fails CI. Theallowsdirection is the one that catches an over-broad
forbidden glob quietly making a policy useless. ci-workflow-fixcarries acautionthatinitprints at adoption time, because write
access to.github/workflowsis a privilege-escalation path and a registry that shipped
it silently would be worse than one that omitted it.- New public helper
is_policy_placeholder, andsignetry_core/policies/ships in the
wheel (confirmed against a built artifact, not assumed).
Changed — licence: open core (BUSL-1.1, converting to Apache-2.0)
signetry-coreis now licensed BUSL-1.1 and converts to
Apache-2.0 on 2030-08-31, replacing the previous "All Rights Reserved"
proprietary terms. You may read, run in your own CI, use in production to govern
repositories you or your organization control, fork, modify, and redistribute it;
the one carve-out is offering it to third parties as a paid, competing hosted
service.pyproject.toml'slicensefield is nowBUSL-1.1.- The integration surface is Apache-2.0: the
Action,
plugins,
pre-commit guard, and
eval suite. - The CLA still applies — open core means code moves across the BUSL/Apache line,
and the assignment is what allows that relicensing without re-asking every past
contributor.CLA.md,CONTRIBUTING.md, andCONTRIBUTORS.mdwere rewritten for
the open-source posture; README/docs/workflow comments no longer claim the project
is "not open source" or "All Rights Reserved". - No functional or API change. Distribution is unchanged: still installed from source
by tag, not published to PyPI. - The CLA's fallback licence grant is now non-exclusive. It previously granted the
Owner an exclusive licence where copyright assignment is not permitted by law, which
would have stripped contributors of the right to use their own contribution — directly
contradicting the rights the LICENSE grants everyone. The CLA text is now identical
across all Signetry repositories (bar the engine/integration licence wording) so the
legal terms cannot drift per-repo again. See CLA.md §2–3.
Fixed
- A scaffold placeholder was reported as declared provenance.
signetry initwritespolicy_owner: your-team, andpolicy_status()reported
declared— "Policy declares a human owner and version (change-controlled
metadata)" — for a file no human had read. Every receipt from a freshly initialised
repo asserted change-control that did not exist. - Placeholder provenance is now treated as absent, with its own status value:
declared/placeholder/incomplete, each carrying anoteexplaining which.
Consumers must treat anything other thandeclaredas not change-controlled; the extra
values exist to say why, which is actionable, and never mean "good enough". - Note for consumers matching on this field: a repo that ran
signetry initand never
edited the provenance keys now reportsplaceholderwhere it previously reported
declared. That is the bug being fixed, not a regression. - Two repo-root-relative links in
docs/RELEASING.mdresolved fromdocs/and were
therefore broken.
Added — Python insecure-deserialisation coverage
marshal.load(s)andshelve.opennow flagged (CWE-502) — both execute arbitrary
code during decoding, and neither was detected.yaml.unsafe_loadflagged, and the Loader is now resolved rather than merely
counted: the previous check treated anyLoader=kwarg as safe, so an explicitly
unsafeyaml.load(x, Loader=yaml.Loader)passed silently.- Gaps identified by @AdvaitVarhade in #87/#91.
Fixed — a positional safe Loader was a false positive
yaml.load(x, yaml.SafeLoader)was flagged, because the old check only inspected
keyword arguments. The Loader is now read from the keyword or the second
positional argument, and matched on its last path segment so bothyaml.SafeLoader
and a bare importedSafeLoaderare recognised.
BUSL-1.1 (Apache-2.0 on 2030-08-31); install from source:
pip install "signetry-core @ git+https://github.com/Signetry/core@v0.8.0"
signetry-core v0.7.0
Added — detection breadth
- Kotlin (
.kt/.kts) is now scanned at all. It was absent from the extension
map, so a Kotlin service or Android app scanned clean regardless of contents.
kotlin.sql_injection(CWE-89) andkotlin.command_injection(CWE-78) match
both the$var/${var}interpolation idiom — which the Java concat-only
patterns miss entirely — and+concatenation. (#52, #93) - Go SSRF —
go.taint.ssrf(CWE-918):http.Get/Head/Post/PostForm,
*Client.Do,http.NewRequest. (#95) - Go and Java path traversal —
go.taint.path_traversal/
java.taint.path_traversal(CWE-22). The Java pattern accepts a qualified
prefix, sonew java.io.FileInputStream(...)matches, not only the imported
short form. (#95) - PHP XXE —
php.xxe(CWE-611), keyed onLIBXML_NOENT/LIBXML_DTDLOADor
libxml_disable_entity_loader(false). Since PHP 8 / libxml 2.9 external
entities are off by default, parsing untrusted XML is not itself the bug —
explicitly re-enabling entities is. (#95) SinkSpec.skip_if— an optional negative guard for taint sinks where a tainted
identifier on the line does not imply taint in the dangerous position. (#97)
Added — executors
AiderExecutor, registered asaider. Fail-closed on both
SIGNETRY_ENABLE_AIDER=trueand the CLI responding. Commit authority stays with
the pipeline (--no-auto-commits,--no-dirty-commits), shell suggestion is
disabled, read-only runs use--dry-run, the--modelvalue is rejected unless it
cannot alter the built command, and the prompt is redacted from the replay
command. (#53, #96)
Fixed — SSRF precision
- The Python SSRF rule now resolves the URL argument independently for keyword and
positional forms.requests.requestwas previously checked atargs[0]— the
HTTP method — making that target effectively dead for positional calls. Adds
httpxput/patch/delete/head/options/request andurllib.requestcoverage.
Thanks @AdvaitVarhade. (#86, #89) urllib.request.Requestremoved from the SSRF sink list: taint already
propagates to theurlopensink, so listing the constructor reported one
vulnerability twice on adjacent lines, where the(file, line, category)dedup
cannot collapse it. (#94)- A constant host with a tainted query string is no longer reported as Go SSRF.
http.Get("https://api.example.com/search?q=" + q)pins the destination, so it
is not SSRF — whilehttp.Get("https://" + userHost)still is, because the
attacker controls the host. (#97)
Fixed — CI
- The advisory reviewer could never comment on a fork PR. Fork PRs get a
read-onlyGITHUB_TOKENregardless of thepermissions:block, so
pull-requests: writewas silently dropped and the comment call returned 403 —
every outside contribution showed a redreviewcheck. Split into an untrusted
job (no write permission, uploads an artifact) and a trustedworkflow_runjob
that posts it and never executes PR code. Deliberately notpull_request_target.
(#92) - The advisory review step's
exit 0 # never fail the PRhad never run: GitHub
invokesrun:steps asbash -e, so a non-zero exit from the reviewer aborted
the step first and any Block verdict turned the check red. (#92)
signetry-core v0.6.0
Changed — renamed to signetry-core (BREAKING)
- Platform renamed to Signetry. The kernel is now signetry-core (import
signetry_core, CLIsignetry). Environment variablesUMBRA_*→SIGNETRY_*,
config directory.umbra/→.signetry/, and receipt/provenance schema
identifiers moved to thesignetrynamespace. No backward-compatible fallbacks. - Install:
pip install "signetry-core @ git+https://github.com/Signetry/core@v0.6.0".
Source-available (All Rights Reserved); install from source:
pip install "signetry-core @ git+https://github.com/Signetry/core@v0.6.0"
umbra-core v0.5.4
Changed — source-available distribution (no PyPI)
- umbra-core is source-available (All Rights Reserved) and is no longer
published to PyPI — all prior PyPI releases were yanked. Install from source:
pip install "umbra-core @ git+https://github.com/bkd-dotcom/umbra-core@v0.5.4". install.shinstalls from the git tag (UMBRA_VERSIONoverrides), not PyPI.release.ymlno longer publishes to PyPI; it builds/tests and cuts a GitHub
Release with the git-source install command.- Docs (SECURITY, INTEGRATIONS, RELEASING, ORG_MIGRATION, docs/site, LAUNCH),
the bundled git hook, the MCP server hints, and the integrations action install
umbra-core from source. No functional/library API change from0.5.3.
Source-available (All Rights Reserved); install from source:
pip install "umbra-core @ git+https://github.com/bkd-dotcom/umbra-core@v0.5.4"
umbra-core v0.5.3
Fixed — Codex sandbox on CI runners
CodexExecutorhonorsUMBRA_CODEX_SANDBOX(read-only|workspace-write|
danger-full-access) so a run can select a sandbox mode that initializes on the
host. On CI runners the OS sandbox (bubblewrap/Landlock) often cannot start, which
madecodex execfail; the operator can now choose full-access drafting there.
Safe because the executor only DRAFTS in a disposable checkout with no push/merge
credentials, and Umbra's admission pipeline governs the result regardless.- The auto-fix workflow sets
UMBRA_CODEX_SANDBOX=danger-full-accessfor CI.
umbra-core v0.5.2
Added — OpenAI/Anthropic-compatible gateway support (e.g. IBM ICA)
CodexExecutoraccepts a custom, syntactically-safe model name when
OPENAI_BASE_URLpoints at a gateway (e.g.gpt-5.5-guson IBM ICA), in addition
to the native allowlist. The strict allowlist still applies toapi.openai.com.- The auto-fix workflow gained
openai_base_url/codex_model/
anthropic_base_url/claude_modelinputs so a run can use a gateway with the
caller's own key (bring-your-own-key), configuring Codex via an isolated
CODEX_HOMEprovider and Claude viaANTHROPIC_BASE_URL+UMBRA_CLAUDE_MODEL.
Verified live on IBM ICA: Codex (gpt-5.5-gus) and Claude (claude-opus-4-8) each
draft a fix that earns L2 through the admission pipeline.
umbra-core v0.5.1
Security — bring-your-own-key safety for --fix
- Redact credential shapes (OpenAI/Anthropic/GitHub/AWS/Google/Slack keys, PEM
private keys, genericsecret=/token=assignments) from any fix diff, receipt,
or artifact before it is serialised — so a governed fix or auto-fix PR can never
carry an executor credential. - Extend the required-check env defense-in-depth denylist (ANTHROPIC/CLAUDE/CODEX/
GEMINI/AZURE/…); the check environment remains an allowlist, so keys cannot reach
a check subprocess by construction. - Every user brings their own key: the executor credential lives only in the
caller's own environment/repo secret, is never shared, never written to git, and
never used to push or merge. Seedocs/AUTOFIX_SETUP.md.
umbra-core v0.5.0
Added — detection engine + governed fix fusion
- Layered SAST detection engine (
umbra_core.pipeline.findings): a
deterministic, offline floor (Python AST taint + regex) across the OWASP set —
SQLi, command/code injection, unsafe deserialization, path traversal, XSS, weak
crypto, insecure randomness, SSRF, SSTI, JWT-none, Django raw SQL, NoSQL, XXE,
hardcoded secrets, TLS-off, debug mode. - Cross-file / interprocedural taint for Python and for Go/Java/PHP/Ruby/C#
(source in one file → call → sink in another). - Multi-language rules + line-based taint for Go/Java/PHP/Ruby/C#, sanitizer-
and parameterised-query-aware (zero-FP oriented). - Optional layers, non-fatal when absent: Semgrep, tree-sitter AST, and LLM
triage (advisory only — never strengthens or self-approves). - SARIF 2.1.0 export and disposable remote-repo clone (
umbra scan <url>). - Fusion:
umbra scan --fix --fix-agent <codex-cli|claude-code>turns each
finding into a bounded remediation mission, runs it through the admission
pipeline, and seals an Ed25519 receipt;umbra-autofix.ymlopens branch-only fix
PRs (never merges). Setup:docs/AUTOFIX_SETUP.md. - CLI:
umbra scanwith--json/--sarif/--output,--fail-on, and the
opt-in--semgrep/--treesitterlayers.
Benchmark (see bkd-dotcom/umbra-eval): 52-case public corpus across 7 languages —
umbra-core 100% recall / 0 false positives vs claude-code-security-review
(Opus 4.8) 90%.
umbra-core v0.4.0
Added — CLI developer experience
umbra initscaffolds a conservative starter.umbra/admission.yaml(loads
cleanly through the real contract loader; refuses to overwrite without--force),
so a new user is one command from a governed change.umbra completion <bash|zsh|fish>prints a shell completion script for the
subcommands (dependency-free;eval "$(umbra completion zsh)").install.sh— acurl … | shone-line installer (uv → pipx → pip, isolated
and fail-closed) and a Homebrew tap (brew install bkd-dotcom/umbra/umbra).- Docs site: a Capabilities & Proof page (capability graph, plan binding,
dual/masked verifier, G1/G2/G3 gates, extension admission) and a refreshed
quickstart.
umbra-core v0.3.0
Added — Admitted Extension (skill / MCP supply chain) + ASBOM
admit_extensiongoverns an agent extension (a skill directory or an MCP
server manifest) as a first-class object — the 2026 supply-chain surface the
per-change pipeline never sees:- Fingerprint — every file (manifest + docs + scripts) is content-hashed into
a stableextension_hash, so "the skill I admitted" is bound by bytes; a later
silent edit changes the hash. - Quarantine before read — documentation surfaces (
SKILL.md, README) and
every MCP tooldescriptionare scanned with the trust-boundary detector; an
agent-directed manipulation is a deny, not an instruction (fail-closed;
--allow-quarantinedis an explicit human override). - Allowlist — when the contract's capability graph declares
allowed_skills
/allowed_mcp, an extension outside it is denied. - Never grants authority — admitting an extension only records that these
exact bytes were reviewed; it does not widen anything.
- Fingerprint — every file (manifest + docs + scripts) is content-hashed into
asbomemits a CycloneDX 1.5-aligned Agent Software Bill of Materials of
admitted extensions (SHA-256 hashes +umbra:verdict/ quarantine properties)
for org inventory.- New CLI:
umbra admit-extension <dir>(--kind,--repofor the allowlist,
--allow-quarantined,--asbom,--org; exits non-zero on deny). New API:
admit_extension,inspect_extension,asbom,AdmittedExtension,
ExtensionFile.
Added — G1/G2/G3 proof gates (Proof Plane)
evaluate_gatesdistills a signed receipt into the three governance gates
the architecture names, so a consumer reads the accountability verdict directly:- G1 Capability integrity — what was this agent allowed to do? Passes when
a plan capability set was bound before the run and the change stayed within it. - G2 Behavioral authenticity — did the checks / sandbox actually run?
Passes only when required checks ran under real isolation (sandboxed/
network-isolated) and passed; ahost-restrictedrun is honestlyunproven. - G3 Interaction auditability — is the history tamper-evident? Passes only
when signed with a non-ephemeral key; strengthened when the receipt is in
the Merkle transparency log.
- G1 Capability integrity — what was this agent allowed to do? Passes when
- Each gate reports
pass/fail/unprovenwith a reason — never a green on
missing evidence.build_receiptnow attaches agatessummary to the envelope. - New CLI:
umbra gates <receipt.json>(exits non-zero unless all gates pass,
so it can gate CI;--jsonfor machine output). New API:evaluate_gates,
Gate,GateSummary.
Added — canonical PR-comment renderer (one template, every surface)
render_pr_commentrenders the frozen GitHub PR-comment template directly
from the Admission Decision Pack ({report, receipt}), so the GitHub Action, a
git hook, and the hosted console all emit the identical pack — no surface can
invent a stronger claim than the receipt. Table (Executor · Contract · Trust
boundary · Checks · Verifier · Proof gates · Receipt · Auto-merge), machine-
readable reason codes, and the L2/L1/L0 conditional line.- New CLI:
umbra comment <report.json>(reads theadmit --jsonpayload from
a file or stdin). New API:render_pr_comment.
Added — capability graph (contract v2)
- Capability-graph contract fields (
.umbra/admission.yaml, all optional and
additive; a contract that declares none behaves exactly as before):allowed_tools— allowlist of agent tool/command names; a tool off the list
is denied.denied_bash— extra shell deny patterns layered on top of the built-in
dangerous-command baseline (a malformed regex fails closed on literal match).allowed_mcp— allowlist ofserverorserver:toolMCP identifiers.allowed_skills— allowlist of skill/plugin identifiers permitted to load.
- Guard API extended:
guard(repo_path, tool=..., mcp=..., skill=...)plus
guard_tool/guard_mcp/guard_skill. Capabilities can only restrict. Contract.has_capability_graphandcapability_graphinto_public()so
surfaces can label a v1 vs v2 policy. The derived flag is excluded from the
rules hash, so an empty capability graph does not change a v1 contract's hash.
Added — independent (masked) second opinion in the verifier
masked_recheck(MELON / ShieldAgent line): correlates the actual changeset
against the manipulation categories the trust boundary detected in untrusted
repository text. When a change does what an injection surface pushed for (e.g.
the README tried to induce secret access and the change now reads env secrets),
it raises a hijack signal.- A hijack signal never blocks (the deterministic path owns blocking) but the
pipeline caps earned authority at ≤ L1 for human review. New verifier fields:
independent_status,hijack_signal,independent_detail(bound into the
signed receipt).
Added — plan capability binding (CaMeL / DRIFT out-of-band control)
PlanCapabilitySetis derived from mission + contract before the executor
runs — a frozen, hashable envelope of what the run may do. It is recorded in the
admission report and signed receipt (answers G1: "what was this agent allowed to
do?"). Only a digest of the mission is bound, never the prose verbatim.- After the run,
evaluate_plan_adherencechecks the actual changeset against the
plan; a deviation caps authority (never widens it). - New API:
derive_plan,evaluate_plan_adherence,PlanCapabilitySet,
PlanAdherence.build_receiptacceptsplan_capability_set/plan_adherence.