Changelog
What each Sealmark release does.
Round 6 (inside 0.3-draft)#
No STANDARD grade moves and the standard hash is unchanged. A server that fronts a backend can be graded with sealmark.yaml alone: Verify a server that fronts a backend.
- Candidate packs
scope,sql-guardandupstream: added when the config declares them, scored in their own pack, labelled in every report, never on the badge (methodology). - Upstream stub and server log.
upstream.kind: httpand{upstream}give the server a harness-owned backend that records every request; what a server Sealmark started prints is read for leaked tokens. - Identities.
{bearer}inserver.headersgives each session a minted caller token (identities.a/.bfor real ones). - Rules in
probes::identity,matrix,cases, a scriptedupstream.reply, andexpect.upstream,expect.logandexpect.response.max_bytes(custom probes). - Two advisory
corecandidates,refusal-qualityandinstructions-hygiene. - A server Sealmark launches with
--startand--urlruns inside the sandbox, so the sandbox packs apply to it. - For agents and CI:
sealmark doctor --jsonand the JSON report carrysuggestions[];sealmark init --probeswrites one valid call per tool (humans, CI and agents).
0.3-draft (methodology)#
Methodology 0.3-draft. This is a methodology change: STANDARD grades and verdicts can differ from methodology 0.2, and the standard hash is new. It is made in one commit so it can be accepted or rejected as one unit. The hash moves because the methodology version moved, net-redirect became a standard check (two settings are now locked), and the unused setting retries.call is no longer locked. A report from methodology 0.2 cannot be replayed (--replay) under 0.3-draft, and a baseline written under 0.2 prints the "different configuration" note. The rule for what counts as a refusal is in Methodology.
What can move a verdict:
- Classification. A parameter with
format: uriorformat: urloutranks a generic parameter plus a name hint, so a URL tool with a generic parameter name is probed by thenetpack. When two candidates tie, both are recorded. The words "git-style" in a description are no longer agitsignal. A required enum declared through$refis resolved, so such a tool can be probed. core.tool-poisoningreads control characters: ESC, NUL and the C1 range are strong, the other C0 controls (not tab, line feed or carriage return) and DEL are weak.robust-inputcounts a read-only tool's no-argument call toward coverage only when the server answered without an error.protocolbounds the tool listing at 5 000 tools or 32 MiB.db. The mutating-SQL corpus grows from 13 to 16 cases:PREPAREandEXECUTEin one call, a side-effect function in theFROMclause, andEXPLAIN ANALYZE. A new advisory candidate,db-privilege, asks whether each server instance connects as exactly the role it was given.fs. Relative-path escapes are probed whenever the relative control works. Move and copy sources are probed. Base64 text, and resource, image and audio blocks returned by a read tool, are decoded and probed. When no escape probe was answered,fs-read-escapeandfs-write-escapeare inconclusive instead of a pass. A high-confidence read tool whose control failed makes the check partial.fs-link-escaperecords evidence on a pass and has an in-root control.git. The repository-scope check probes a sibling whose name has the configured repository's path as a prefix, and argument injection reaches optional string parameters declared withanyOf,oneOfor$ref.net.net-capsjudges the size half by the bytes the listener sent,net-loopback-ssrfrecognises more refusal wording, and adata:URL accepted as an embedded resource, or by a tool already shown to fetch, is partial.net-redirectis promoted: it is scored, not critical and standard.sqlite. A declared writer tool is probed for file writes, file reads and extension loading, and any one tool that reads or writes another file now fails those two checks (before, one clean tool softened it to partial).exec. A reply that says "killed" is confirmed against the process table: a harness program that is still running makesexec-timeout-capfail.- Exit policy. The
ciprofile counts an inconclusive pack as a failure at the gate (treat_inconclusive_as: fail), and a provisionalA*does not meet the default A gate. - Configuration.
retries.callis deprecated, unlocked and ignored: nothing retries a control call. Old files that set it still load, with a warning. - Second verification round. The merged build was re-checked against real public servers; no locked setting changed, so the standard hash is expected to stay as it is. A refusal must tie itself to the target, a server that re-validates redirects can pass
net-redirect, thefs-write-escapecorpus mirrors the read corpus, thegitpack needs{sandbox}in the config, coverage counts only calls the server processed, and custom checks or plugins give a run its ownconfig.hash.
Control-character tiers, the fs zero-probe guard, the exec confirmation, the promotion of net-redirect, db-privilege as an advisory candidate, retries.call and the ci and A-gate rules were open owner decisions. They are decided by recommendation, owner may veto.
Output that does not move a verdict:
- Each check line carries one verdict tag, advisory checks end with
(advisory, not scored), and the score is points over scored checks in every format. Thepacks appliedline lists every pack that ran,coreincluded. - Two runs of the same server give the same verdicts and evidence: the listener port, sandbox paths and per-run tokens are fixed placeholders, and the text, markdown, summary, badge and shields formats are byte-identical at every verbosity (JSON, JUnit and SARIF differ in timing fields and
sandbox.listenerPort). - After a signal (exit codes 129, 130, 143) the harness starts no further server and removes the sandbox, the seed database and any embedded Postgres. The
no badge:messages name the reason, andsealmark config showsays whether the configuration is STANDARD or CUSTOM. - The docs site is generated from the built CLI again, and the site build fails when the generated pages differ from what the CLI prints.
0.2.1#
Methodology 0.2, unchanged. STANDARD grades and the standard hash are unchanged: a default run with the default configuration gives the same letters, the same verdicts and the same config.hash as 0.2.0, for every server. Nothing below is scored, and nothing below is a locked setting.
- Candidate checks, and the first one:
net-redirect. A check can ship ahead of the standard: advisory, listed in every report, outside the standard hash. Switching one off or scoring it makes the run CUSTOM.net-redirect(packnet) asks whether a URL tool follows a redirect served by the harness's loopback listener, whether it re-validates the target, and whether it follows one to afile:or raw-TCP URL. It isn/aunless the server already fetched the listener. See net-redirect and Candidate checks. - Tool-surface drift.
server.surfacein the JSON report records hashes and types, never descriptions.--fail-on driftexits 1 on a breaking or notable change against a baseline, andsealmark diff <before.json> <after.json>compares two reports without running a server.--fail-onis now a list (any,regressions,drift;output.fail_onin a file);output.exit_policy.regressions_only: truestill means[regressions]. See drift. - README badge.
--format badge(SVG) and--format shields(shields.io endpoint). Self-reported, one server, never a letter for a custom or core-only run. See badge. - Fixtures.
--fixture fs,gitandsqlitewith--into <dir>write the layout, repositories or database the sandbox generates.--fixture duckdbstill exits 2. - Staged files.
server.files(andservers.<name>.files) writes small files into the sandbox before the server starts. Configuration file only. - Changed text: the not-covered line for SSRF now says that redirects from a public host to loopback and DNS rebinding are not tested;
describe --jsonlistscandidatefor each check; the CI jobs pinsealmark@0.2.1.
Left as they were, by decision: promoting net-redirect into the standard, scoring drift, and the other changes that would move a grade or the hash are 0.3-draft decisions for the owner.
0.2.0#
Methodology 0.2.
- Breaking: the default gate is A.
sealmark runexits 1 for any graded pack below an A, in every profile. Before 0.2.0 there was no gate unless you passed--fail-under. Relax it with--fail-under B,C,DorF, turn it off with--fail-under none, or keep it and exit 0 with--soft-fail. - The
ciprofile sets no gate.--fail-underno longer opts a run out of theciprofile underCI=true; only--out,--formatand--out-dirdo. - Packs:
sqlite,fs,git,net,http,effects, the opt-inexec, and customprobes:, next tocoreanddb. - Configuration: layered files, profiles,
sealmark.local.yaml,SEALMARK_*environment variables,${VAR}references,tools.includeandtools.exclude, strict validation of unknown keys, and the STANDARD or CUSTOM label. - Commands:
doctor,list-checks,explain,describe --json,config show,config profiles,config migrate, andinit --ci gitlab|github. - CI:
--startwith--urllaunches, tests and stops a server;--header,--bearer,--start-timeout,--name,--soft-fail; CI auto-detection. - Output:
markdown,junit,sarifandsummarynext totextandjson;--out-dir;--baseline,--write-baselineand--fail-on. - Database checks:
cap-timeoutis retired in favour ofdb-rowcapanddb-timeout, andpii-maskedis new.
0.1.0 (2026-10-09)#
Methodology 0.1, seed 0.1. The first release: sealmark init and sealmark run, with exit codes 0 to 4 (a run that grades nothing exits 3) and a text or JSON report that records the exact server command, environment, tools found and evidence for every check, plus a "Not covered" list.
core:protocol,tool-poisoning(critical),robust-inputandsecret-echo(critical, n/a over HTTP).db:read-only,mutating-sql(critical, a 13-case corpus),rls(critical),pii(critical),cap-timeout, and the advisorywrite-gateandaudit, run once per database role against a seeded synthetic database in an embedded Postgres (or your own with--pgand--yes). Controls run before judging, so a broken connection is inconclusive, never a pass.- Grading: the same formula as today (see Methodology).
- Windows:
PATHEXTandCOMSPECare added to the server's environment, and the server's whole process tree is killed at the end of a run.
What is designed but not built is on the roadmap.