justdocs v0.1.0
justdocs 0.1.0
- release tag:
v0.1.0 - target commit:
4b579aa74001c955dba511550e364ee196db60d0 - previous release: none
Included commits
13a2fd8Initial commitdc28c39Add justdocs MkDocs theme package- Package justdocs 0.1.0 with setuptools metadata, Python 3.10+ support,
MkDocs >=1.6,<3, console script, theme entry point, and linker plugin entry
point. - Include theme templates, static CSS/JS assets, Mermaid license text, and the
project Justfile template as setuptools package data. - Add
justdocs theme-dirto validate and print the bundled MkDocs theme path. - Add
justdocs initto write project-local Justfiles with root, MkDocs config,
bind address, package spec, and forced overwrite controls. - Add typed asset errors for incomplete theme and project template bundles.
- Add project Justfile generation with frozen config, address-derived port,
placeholder replacement, existing-file preservation, forced regeneration, and
editable install flag rejection. - Add source Justfile recipes for package install, theme path lookup, unit tests,
generated example Justfile refresh, strict example build, serve, and aggregate
check. - Add generated project recipes for install, check/build, serve, serve-clean,
free-port, clean, dist-clean, env overrides, local source install locking via
flock, andpymdown-extensions==10.12. - Add MkDocs theme config extending stock MkDocs with 404 template, navigation
depth, primary nav style, color mode, and user color mode toggle. - Add base, main, and 404 templates for topbar, left navigation, right TOC,
pagination, mobile navigation, search, theme toggle, preferences, sidebar
controls, sidebar resizers, sidebar restore buttons, and drawer scrim. - Inject
extra.justdocspalette, typography, shape, layout, preference,
feature, sidebar, breakpoint, and search values into CSS tokens and
window.JUSTDOCS. - Add theme CSS for responsive grid layout, drawer/mobile states, collapsible
sidebars, resizable rails, preferences, search results, light/dark tokens,
table labels, mobile table cards, code blocks, linked inline code, Mermaid
blocks, reduced motion, and print output. - Add theme JS for viewport state, topbar height sync, sidebar width clamping,
localStorage sidebar state, pointer and keyboard resizing, preferences
persistence, preferences reset, local search loading, result scoring, snippet
highlighting, navigation scroll persistence, theme switching, table labels,
Highlight.js setup, code copy setup, and Mermaid render/re-render. - Bundle Highlight.js v11.9.0 GitHub Dark CSS/JS, copy-button CSS/JS with
browser global export, Mermaid JS, and Mermaid MIT license text. - Add
justdocs-linkerto collect heading, page-stem, and action-ID targets;
remove stop phrases and ambiguous targets; normalize whitespace, dashes, and
case; compute relative URLs; protect fences, links, reference definitions,
tags, headings, and inline code; and bound links per page and per target. - Link inline action IDs matching
P\d+-\d{4}while preserving fenced code and
existing Markdown links. - Add an executable example site with search,
justdocs-linker,
pymdownx.highlight, Mermaid superfences, TOC permalinks, complete
extra.justdocsconfiguration, and pages covering Service Discovery,
Deployment Guide, Traffic Policy, tables, code, and Mermaid. - Add reference content recording theme, search, smart-link, and complexity
contracts, including O(n), O(p * q), and O(p * t * s) operation bounds. - Expand README from a stub into package, configuration, CLI, generated recipe,
source command, and runtime behavior reference. - Add audit artifact mapping project Justfile generation files, flows, guards,
deterministic invariants, scope completion, and verification evidence. - Ignore generated
examples/**/site/outputs. - Add 23 unittest cases covering packaged assets, template availability,
Justfile rendering, overwrite refusal, forced overwrite, editable package spec
rejection, theme metadata, template assets, sidebar controls, preferences,
Mermaid, code copy, feature gates, CSS layout contracts, example config,
relative URLs, prose/table smart links, and inline action-ID links.
- Package justdocs 0.1.0 with setuptools metadata, Python 3.10+ support,
ba6433bRefresh Justdocs docs and example contract coverage- Expand the README into a complete Justdocs reference for package metadata,
Python and MkDocs requirements, console script binding, theme entry point,
plugin entry point, packaged theme assets, and the project Justfile template. - Document the full MkDocs integration surface with
search,
justdocs-linker, tables,pymdownx.highlight, Mermaid superfences, TOC
permalinks, and the completeextra.justdocsconfig shape. - Define every documented theme config default for title, favicon, palette,
typography, shape, content width, density, motion, breakpoints, sidebars,
preferences, feature gates, and client search limits. - Add browser runtime contracts for viewport datasets, compact topbar state,
small viewport state, theme, density, content width, motion, sidebar state,
sidebar widths, nav scroll storage, search index resolution, search scoring,
Mermaid initialization, and sidebar resizing keys. - Document
justdocs theme-dirandjustdocs initCLI behavior, including
asset validation, generated Justfile output, init flags, overwrite policy, and
typed failure classes. - Document generated project recipes for install, check, build, serve,
serve-clean, free-port, clean, and dist-clean, including every
JUSTDOCS_*environment override. - Record local source install locking through
flock, lock directory layout,
extra package installation withpymdown-extensions==10.12, and editable
install rejection. - Add source-repo recipe docs for local package install, theme path lookup,
example Justfile regeneration, unit tests, strict example build, example
serve, and aggregate check. - Define
justdocs-linkerplugin config defaults for enabled state, minimum
phrase length, per-page link cap, and per-target link cap. - Document smart-link target generation from page H1s, ATX headings, file
stems, action stems, and action IDs. - Document smart-link filtering for stop phrases, ambiguous phrases, phrase
eligibility, deterministic ordering, and current-page exclusions. - Document protected Markdown ranges for fenced code, existing links, reference
definitions, HTML tags, ATX headings, inline code, and linkable inline action
IDs. - Add complexity bounds for target collection, target dedupe, protected range
merging, smart-link passes, theme asset validation, template rendering, and
search scoring. - Add packaged asset and runtime error reference tables covering required theme
files, Highlight.js assets, copy-button assets, Mermaid assets, template
files, search failures, missing controls, and missing browser globals. - Replace the example service-topic docs with Justdocs-specific pages for
Theme Configuration, Project Setup, Smart Links, and Reference. - Update the example index to exercise the current docs graph, runtime feature
table, required MkDocs plugins, Mermaid rendering, Python API snippet, and
mobile table label behavior. - Add explicit example nav entries for Theme Configuration, Project Setup,
Smart Links, and Reference inexamples/basic/mkdocs.yml. - Remove obsolete Service Discovery, Deployment Guide, and Traffic Policy
example pages from the staged docs surface. - Extend docs tests to require the new example nav entries, verify README and
example docs both cover current contract terms, and reject stale service-topic
terms from the example docs. - Update smart-link table/prose tests to use current Justdocs page targets while
preserving coverage for tables, prose, inline code protection, existing link
preservation, and Mermaid fenced code protection. - Keep staged scope to 11 files with 648 insertions and 117 deletions across
README, example docs, example nav, and docs coverage tests.
- Expand the README into a complete Justdocs reference for package metadata,
15edb7eperf: compile smart-link targets into one match graphBuild a compiled smart-link graph during MkDocs file discovery and reuse it
while each page is linked, replacing repeated per-target regex scans with one
aggregate matcher plus normalized-key lookup.Smart-link compilation:
- Replace per-target compiled regex storage with normalized target keys and
reusable pattern text. - Add
CompiledLinkGraphfor compiled targets, exact-key target lookup, and an
optional aggregate regex. - Build empty target sets as
pattern=Noneso link segments return unchanged
without regex work.
Linking behavior:
- Change
_link_segment()to search the aggregate regex from each cursor
position instead of scanning every target pattern. - Resolve matches through normalized
match.group(0)keys before applying
self-link and per-target cap checks. - Keep unmatched, current-page, and cap-exhausted matches as plain text.
- Reuse the compiled key lookup for inline action-ID code references.
Plugin lifecycle:
- Store
_link_graphonJustdocsLinkerPlugininstead of raw targets. - Reset disabled or empty plugin state to an empty compiled graph.
- Compile deduped page candidates once in
on_files()and pass the graph into
page-level Markdown linking. - Keep
_smart_link_markdown()compatible with tuple target inputs by compiling
only when callers have not suppliedCompiledLinkGraph.
Checks:
git diff --cached --checkPYTHONDONTWRITEBYTECODE=1 PYTHONPATH=. python3 -m unittest discover -s tests
(Ran 24 tests in 0.006s,OK)
- Replace per-target compiled regex storage with normalized target keys and
60a3900Remove audits dir829dc62Add GNU GPL v3 license fileAdded the GNU General Public License version 3 to the project.
912a5c5Update README with public status noteUpdated README to reflect public status change.
26b4d58Update repository visibility and license note550dd8cFix punctuation in README note about repository status5dff853feat: ship installable justdocs CLI and release automationExpose justdocs as a user-global command without cloning, mirror generated
project recipes through the installed CLI, add package self-maintenance commands,
and wire the repository for validated Python distribution releases.Global Installation:
- Add executable
install.shforcurl -fsSL .../install.sh | shinstalls. - Add
install.ps1forirm .../install.ps1 | iexWindows installs. - Default bootstrap installs to the GitHub
mainarchive at
https://github.com/FanaticPythoner/justdocs/archive/main.tar.gz. - Support
JUSTDOCS_INSTALL_SOURCE=github,pypi, andurlacross both
bootstrap installers. - Support exact PyPI versions with
JUSTDOCS_INSTALL_VERSION. - Support full pip requirement overrides with
JUSTDOCS_INSTALL_SPEC. - Support custom archive URLs with
JUSTDOCS_INSTALL_URL. - Support custom repositories and refs with
JUSTDOCS_REPOSITORYand
JUSTDOCS_INSTALL_REF. - Add
JUSTDOCS_INSTALL_DRY_RUNso CI can assert resolved pip commands without
mutating global user state. - Require Python 3.10+ before invoking pip in both bootstrap installers.
- Use
ensurepip --userwhen pip is absent before global install. - Verify the installed
justdocscommand resolves from the selected
interpreter user scripts directory. - Fail when
justdocsis absent fromPATHor shadowed by another command. - Add source-tree
just global-installandjust install-globalaliases. - Add source-tree
just global-uninstallandjust uninstall-globalaliases. - Route source global install and uninstall through
justdocs.global_cli. - Validate source installs by
pyproject.tomlpresence before invoking pip. - Detect platform console script names for POSIX and Windows user script dirs.
- Verify uninstall by checking that user script candidates were removed.
- Share cross-platform source install locks through
justdocs.install_support.
Project Recipe CLI:
- Make bare
justdocsexit successfully with parser help and common commands. - Add
justdocs projectandjustdocs projectsnamespaces. - Expose
init,install,check,build,serve,serve-clean,
free-port,clean, anddist-cleanas CLI recipe equivalents. - Preserve
justdocs initas the direct project Justfile generator. - Add
ProjectRecipeConfigfor root, MkDocs config, bind address, port,
package spec, extra packages, virtualenv path, and Python executable. - Resolve virtualenv paths under the selected project root.
- Create virtualenvs only when the configured interpreter is missing.
- Run project installs as virtualenv pip commands.
- Upgrade pip before installing the configured package and extra packages.
- Reuse
split_package_specso CLI recipes inherit editable-install rejection. - Serialize local source package installs with the shared install lock.
- Run strict MkDocs builds as
mkdocs build -f <config> --strict --clean. - Implement serve and serve-clean through the configured address.
- Validate free-port inputs as TCP ports in
1..65535. - Use
lsoforfuserfor POSIX listener discovery. - Use
netstat -ano -p TCPandtaskkill /Ffor Windows listener cleanup. - Remove
site,.cache,.mkdocs_cache, and the configured virtualenv for
cleanup recipes.
Version And Package Maintenance:
- Add
justdocs versionandjustdocs version --json. - Add
justdocs version --checkto combine installed version output with
remote metadata checks. - Add
justdocs self check-updatewith PyPI JSON and GitHub latest release
sources. - Add
justdocs self updatewith PyPI and GitHub release tag install targets. - Parse versions through
packaging.version.Versionfor PEP 440 ordering. - Normalize GitHub tags by removing a leading
v. - Report malformed PyPI and GitHub metadata through
UpdateCheckError. - Report pip install failures through
UpdateInstallError. - Resolve GitHub repository slugs from installed package metadata Project-URL
entries. - Emit JSON result payloads for automation consumers.
Release Automation:
- Add a reusable
build-distcomposite action around the release build script. - Add a reusable
release-assetscomposite action for GitHub Release create,
edit, purge, and upload flows. - Add CI for Python
3.10,3.11,3.12,3.13,3.13t,3.14, and
3.14t. - Add CI coverage on
ubuntu-24.04,macos-15, andwindows-2025. - Build and upload distribution artifacts from the Python
3.12CI row. - Add a reusable workflow to build Python distributions from an arbitrary ref.
- Add a tagged release workflow for
v*.*.*pushes and manual existing-tag
dispatch. - Validate release tags against
pyproject.tomlversion before publishing. - Require the release tag commit to be reachable from
origin/main. - Publish to PyPI through
pypa/gh-action-pypi-publish@release/v1only when
PYPI_API_TOKENexists. - Stage only
.whland.tar.gzfiles intoartifacts/pypi. - Attest wheel and sdist provenance through
actions/attest-build-provenance. - Verify public PyPI visibility after credentialed publishes.
- Add a scheduled and push-triggered
latestprerelease workflow formain. - Generate release notes from commits since the previous semantic version tag.
- Stage
install.shandinstall.ps1with release assets. - Generate
SHA256SUMS.txtover release installers, wheel, and sdist. - Add Dependabot coverage for pip and GitHub Actions dependencies.
- Add CodeQL analysis for Python and GitHub Actions.
- Add dependency review for pull requests.
Packaging Metadata:
- Raise the build backend requirement to
setuptools>=77. - Add
README.mdas package readme metadata. - Add SPDX license metadata with
GPL-3.0-only. - Add
license-files = ["LICENSE"]. - Add
packaging>=24,<26as a runtime dependency for version ordering. - Add Python
3.14and free-threading classifiers. - Add CPython, MkDocs, console, developer audience, and documentation topic
classifiers. - Add Homepage, Repository, Issues, and Releases project URLs.
- Ignore generated release artifacts while keeping audit markdown files tracked.
Documentation And Audit Artifacts:
- Document no-clone POSIX and PowerShell bootstrap install commands.
- Document bootstrap environment variables and PATH verification failures.
- Document global install and uninstall source recipes.
- Document project recipe CLI command parity.
- Document version checks, package self-maintenance commands, and release flows.
- Document PyPI credential gating and GitHub release asset behavior.
- Add example docs coverage for bootstrap installers and release automation.
- Add reference docs for
ProjectRecipeConfig,ProjectRecipeError,
GlobalCliError,UpdateCheckError, andUpdateInstallError. - Add audit artifacts mapping file roles, flows, invariants, fixed locations,
scope completion, tests, and complexity for global CLI and release work.
Tests:
- Add contract coverage for source Justfile global install recipes and aliases.
- Add project init alias coverage for
justdocs projects init. - Add no-arg CLI command hub coverage.
- Add project recipe dispatch coverage for CLI arguments and environment
override plumbing. - Add PyPI and GitHub version candidate selection coverage.
- Add current-version and PEP 440 ordering coverage.
- Add pip command construction coverage for PyPI and GitHub updates.
- Add CLI self-update dispatch coverage.
- Add release workflow assertions for setup-python v6, PyPI publishing,
artifact staging, release actions, Python 3.14, and free-threaded rows. - Add bootstrap installer assertions for shell syntax, default GitHub archive
dry-run, explicit PyPI dry-run, and tagged GitHub archive dry-run. - Add global CLI script candidate coverage for POSIX and Windows names.
- Add locked user pip install coverage for source global install.
- Add uninstall verification coverage for global CLI removal.
- Add project recipe install coverage for venv creation, pip upgrade, package
install, extra packages, and lock use. - Add project recipe strict MkDocs command coverage.
- Add project clean and invalid free-port coverage.
- Extend docs coverage required terms to CLI, release, installer, and package
metadata contracts.
Checks:
git diff --cached --checksh -n install.shbash -n scripts/release/build-python-package.sh scripts/release/release-artifacts.sh scripts/release/release-versioning.sh scripts/release/resolve-release-metadata.sh scripts/release/verify-pypi.sh scripts/release/write-release-notes.shJUSTDOCS_INSTALL_DRY_RUN=1 JUSTDOCS_PYTHON=$(command -v python3) sh install.shJUSTDOCS_INSTALL_DRY_RUN=1 JUSTDOCS_PYTHON=$(command -v python3) JUSTDOCS_INSTALL_SOURCE=pypi sh install.shJUSTDOCS_INSTALL_DRY_RUN=1 JUSTDOCS_PYTHON=$(command -v python3) JUSTDOCS_INSTALL_SOURCE=github JUSTDOCS_INSTALL_REF=v0.1.0 sh install.sh.venv/bin/python - <<'PY' ... yaml.safe_load(...) ... PYjust testjust checkjust dist
Measurements:
- Staged diff: 33 files changed, 3156 insertions, 32 deletions.
- Workflow parse: 9 YAML files parsed.
- Unit suite: 44 tests passed.
- Strict docs build: documentation built in 0.14 seconds.
- Distribution validation: wheel and sdist passed Twine checks.
- Release artifact set:
SHA256SUMS.txt,install.ps1,install.sh,
justdocs-0.1.0-py3-none-any.whl, andjustdocs-0.1.0.tar.gz.
- Add executable
d87e960feat: unify CLI project, install, update, and release flowsReplace alias-heavy user-site lifecycle paths with canonical
projects
commands, stored project configuration, isolated platform installers,
release-wheel updates, and reproducible PEP 440 release automation. Enforce
ownership, path confinement, bounded metadata, deterministic lock order,
atomic writes, publication authentication, and synchronized documentation.CLI contract:
- Make
projectsthe sole project namespace withinit,install,check,
build,serve,serve-clean,free-port,clean, anddist-clean. - Move update discovery and installation to top-level
check-updateand
update; default update source selection toautoacross PyPI and GitHub. - Remove top-level
init, singularproject, nestedselfcommands,
version --check,update --user, and source recipe aliases
install-globalanduninstall-global. - Load theme, project, and update modules only for matching commands so bare
help and version lookup avoid unrelated engines. - Read installed version solely from distribution metadata through the new
versionmodule; remove the static package__version__fallback and fail
explicitly when metadata is absent. - Centralize package name, 3-second network timeout, default address, and
default extra-package requirement inconstants.py. - Report exact updated/current outcomes and preserve partial source failures as
stderr warnings.
Project configuration:
- Persist schema-1, sorted, ASCII-safe JSON in the first generated Justfile
line with exactmkdocs_config,addr,package,extra_packages, and
venvfields. - Bound stored configuration reads to 65,536 bytes and reject symlinks,
non-regular files, non-UTF-8 text, malformed JSON, unknown or missing fields,
non-string values, and unsupported schemas. - Resolve project settings by CLI option,
JUSTDOCS_*environment value,
stored Justfile value, then package default; derive port from the effective
address when no explicit port exists. - Validate template marker cardinality and JSON-escape quotes, newlines, and
shell-shaped values before rendering. - Write generated Justfiles through same-directory temporary files,
fsync,
mode preservation, and atomic replacement; replace forced symlinks without
following their targets. - Preserve PEP 508 requirements, URLs, and filesystem paths with spaces as
single pip arguments while rejecting empty specs and every pip option token. - Replace 43-line Bash-specific generated recipes with 28-line,
platform-neutral delegates tojustdocs projects; retain all eight recipe
names. - Add Windows PowerShell shell selection, platform Python defaults, canonical
example generation, and repository-venv PATH injection to the source
Justfile.
Project execution and locking:
- Lock the configured virtualenv plus every local source package from primary
and extra requirements in deduplicated lexical order across venv creation
and pip installation. - Remove the independent pip self-upgrade from project installation.
- Secure shared install-lock storage with canonical full SHA-256 names, POSIX
owner checks,0700root mode,0600file mode, and symlink rejection. - Restrict virtualenv paths to strict descendants of the resolved project root,
including symlink-mediated paths. - Unlink output symlinks without traversal, reject regular-file cleanup
targets, and translate filesystem failures into project errors. - Reject malformed POSIX and Windows listener PIDs, preserve the
1..65535
port invariant, and translate subprocess launch failures. - Reject Boolean and nonpositive integer values for linker limits during
MkDocs configuration. - Preserve existing theme/template asset resolution and smart-link transforms;
limit new linker behavior to configuration-bound validation.
Bootstrap installers:
- Replace current-interpreter user-site installs with isolated managed roots at
$HOME/.justdocson POSIX and%LOCALAPPDATA%\justdocson Windows. - Create a dedicated virtualenv and managed
bin/justdocs[.exe]command;
verify command execution withjustdocs version. - Resolve the default GitHub source from the latest-release API and select
exactly onejustdocs-*-py3-none-any.whl; retain explicit PyPI, URL,
source-spec, and GitHub-ref archive modes. - Bound release metadata to 2 MiB with a positive finite 10-second default
timeout; validate repository syntax, UTF-8 JSON shape, tag presence, asset
count, HTTPS GitHub host, and filename agreement. - Require Python 3.10 or newer and reject invalid Boolean controls or specs
beginning with pip options. - Require the
justdocs-managed-v1ownership marker and reject filesystem
roots, user-home roots, Windows reparse roots, nonempty unmanaged roots,
invalid markers, and unowned commands. - Serialize installer mutation through recoverable POSIX PID locks or exclusive
Windows file locks; reject live lock owners. - Require exact managed symlink ownership on POSIX and SHA-256 executable
equality on Windows before replacement or removal. - Manage POSIX shell/fish profile blocks and Windows user PATH idempotently;
reject malformed POSIX marker blocks and remove duplicate Windows entries. - Expose dry-run output for venv, pip, command, and PATH operations without
acquiring the install lock or mutating the managed root. - Route source-tree global install and uninstall through the same platform
bootstrappers with explicit action, source root, and interpreter environment.
Self-update:
- Bound PyPI and GitHub JSON to 2 MiB, require positive finite timeouts, and
distinguish HTTP 404 publication absence from transport or metadata failure. - Deduplicate requested sources, retain source warnings when a candidate
survives, and fail when transport errors leave no candidate. - Normalize versions with PEP 440 and select the newest candidate across
enabled sources. - Derive the GitHub repository only from canonical installed HTTPS metadata;
remove the hardcoded repository fallback. - Require canonical release HTML metadata and exactly one version-matched
py3-none-anywheel with an HTTPS GitHub download URL. - Install GitHub updates from release wheels instead of VCS checkouts.
- Reject downgrades and explicit versions with ambiguous
autosource; return
without pip execution when the installed version is current. - Infer
--useronly for base-interpreter distributions under user site and
omit it for virtualenv or system distributions. - Re-read installed metadata after pip and require exact normalized target
version equality.
Packaging and release automation:
- Pin
setuptools==83.0.0, add release extrasbuild==1.5.1and
twine==6.2.0, and widen runtime packaging topackaging>=24. - Seed builds with
PYTHONHASHSEED=0and the latest commit timestamp as
SOURCE_DATE_EPOCH. - Repack sdists in sorted PAX order with gzip mtime zero, normalized member
timestamps, zero UID/GID, empty owner names, and cleared pax headers. - Replace regex tag ordering with
packaging.version.Version, discard invalid
PEP 440 tags, and derive prerelease state fromVersion.is_prerelease. - Require the release tag to equal the raw
pyproject.tomlversion and retain
tagged-commit ancestry verification against remotemain. - Percent-encode PyPI verification paths, use a 15-second interval,
600-second deadline, and 10-second request cap, reject non-finite bounds,
cap responses at 2 MiB, and require exact published-version equality. - Prefer PyPI trusted publishing, fall back to API-token authentication with
publisher attestations disabled, skip publication when neither is
configured, record the mode, and retain independent provenance attestation. - Stage sorted wheel and sdist artifacts through the shared release inventory
helper; remove inherited secrets and the unused reusable-build
release_taginput. - Install Python 3.12 plus
packaging>=24before stable and nightly release
note generation.
Documentation and tests:
- Rewrite README and example project/reference docs for canonical commands,
release-asset bootstrap URLs, isolated roots, PATH controls, uninstall,
stored-config precedence, typed errors, update semantics, and publishing
authentication. - Remove stale raw-main installers, user-site behavior, legacy command aliases,
static version claims, and thepackaging<26contract from documentation. - Expand
tests/test_package.pyfrom 44 to 75 test methods with project JSON,
atomic/symlink writes, package parsing, CLI removals, and config precedence
coverage. - Add update tests for 404 handling, canonical repository and wheel metadata,
2 MiB bounds, PEP 440 selection, exact pip commands, no-op, downgrade,
ambiguous source, pip scope, and post-install verification. - Add installer tests for platform dry-runs, latest-wheel resolution, ownership
refusal, preserved external targets, stale/live locks, invalid controls, and
bootstrap delegation. - Add release tests for trusted/token publication, deterministic build markers,
PEP 440 tag ordering, polling bounds, artifact staging, and removed workflow
secret/input surfaces. - Add project-runtime tests for deterministic multi-root locking, strict MkDocs
builds, confined cleanup, symlink unlinking, PID parsing, and linker limits. - Enforce docs freshness by requiring canonical surfaces and rejecting removed
aliases and stale taxonomy.
Algorithmic bounds:
- Let
Lbe first-line bytes; read stored configuration in
O(min(L, 65,537)) time and space. - Let
rbe lock roots; discover and sort them in O(r log r) time and O(r)
space. - Let
abe release assets; filter them in O(a) time and O(a) candidate space. - Let
mbe sdist members andbpayload bytes; normalize them in
O(m log m + b) time, O(m) memory, and O(b) temporary disk. - Let
Tbe polling duration andiinterval; issue at most
floor(T / i) + 1 requests when request duration approaches zero.
Checks:
PYTHONDONTWRITEBYTECODE=1 just check: 75 tests pass; strict example build
completes.PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=. .venv/bin/python -m unittest discover -s tests: 75 tests pass in 0.973s.ruff check .: pass.ruff format --check .: 14 files already formatted.sh -n install.shplus Bash syntax checks for staged release scripts: pass.git diff --cached --check: pass.PYTHONDONTWRITEBYTECODE=1 python3 -m unittest tests.test_package: 74 of
75 pass;test_release_versioning_orders_pep440_tagsreceives no tags
because the staged helper invokes unavailablepythonandmapfilemasks
that process-substitution failure.
Measurements:
- Staged delta: 28 files, 3,090 insertions, 876 deletions, two new modules.
- Test inventory: 44 -> 75 methods, +31 net.
- Repo-native test run: 75 tests in 1.087s; example documentation build in
0.15s.
- Make
2493c0cfeat: make release publication transactionalReplace direct tag mutation and unverified asset uploads with a versioned,
journaled release transaction that snapshots immutable inputs, verifies remote
identity around every mutation, and converges through commit-forward or
rollback. Reconcile PyPI by exact filename and SHA-256 sets, pin workflows to
immutable commits and artifact digests, tighten dependency automation, and add
deterministic fault-injection coverage.Transactional GitHub releases:
- add
preflight,publish, andcleanupcommands with typed errors, exit code
2, SIGINT/SIGTERM handling, and exclusive per-transaction locking - model release assets, release state, and transaction metadata as frozen data
classes updated through immutable replacements - persist schema-version-4 journals as compact sorted JSON through exclusive
temporary files, file and directory fsyncs, and atomic replacement - track original and target tag SHAs, original and prepared release snapshots,
desired metadata, desired asset digests, created release identity, owned asset
IDs, and transaction phase - enforce phase invariants across
preflight,prepared,mutating,tagging,
committing,committed,rolled_back, androlled_back_with_tag - reject malformed journals, unknown fields, invalid IDs, invalid digests,
inconsistent snapshots, noncanonical parents, repository drift, and boundary
escapes - validate repository identity, tag syntax, Boolean operands, target commit, and
transaction parent before creating a journal - resolve target commits through GitHub and require tags without movement enabled
to reference the exact release commit - compare existing
latesttargets against the requested commit and permit only
aheadoridenticalmovement - compare-and-set remote tags against the preflight SHA, use non-forced ref
updates, and verify the resulting target - sample release metadata before and after paginated asset enumeration to reject
concurrent release changes - validate positive release and asset IDs, strict Boolean fields, unique asset
names, uploaded or starter states, sizes, content types, and SHA-256 digests - reject incomplete existing uploads before mutation
- verify staged snapshots, notes bytes, asset hashes, and asset sizes before
preparation and again immediately before uploads - create absent releases as marker-owned drafts tied to the exact target commit,
persist the created ID, apply desired metadata, upload assets, and publish only
after exact prepared-state verification - transform existing releases into non-latest drafts, rename selected originals
to database-ID rollback names, upload replacements, move the tag, delete
retained originals, and publish in deterministic order - preserve noncolliding original assets when purge is disabled and replace the
complete original inventory when purge is enabled - upload through verified regular-file descriptors under deterministic temporary
names derived from the transaction and final filename - persist every returned upload ID before further mutation, rename uploads into
final names, and verify ID, label, MIME type, digest, size, and uploaded state - treat exact immutable releases as mutation-free committed transactions and
reject immutable releases that differ from staged metadata or assets - recover
taggingandcommittingjournals by completing publication forward,
including accepted publish or delete operations whose client call failed - recover
mutatingjournals by deleting transaction-owned assets, restoring
original asset names and metadata, restoring release flags and text, or
deleting a marker-owned newly created release - preserve an implicitly created target tag as
rolled_back_with_tagwhen no
original tag existed, permitting a later independent transaction to converge - delete transaction-owned starter uploads left by failed asset requests
- reject and preserve unknown concurrent assets, externally replaced drafts,
reserved-name collisions, asset-ID drift, and indeterminate ownership - retain recovery journals when rollback cannot prove safe ownership
- recover active journals during cleanup and remove transaction directories only
after reaching a terminal phase - use GitHub GraphQL for stable release and tag snapshots and REST API version
2026-03-10for commit, comparison, ref, release, and asset operations
Release-input snapshots:
- add
stage,verify, andcleanupcommands with snapshot schema version 2 - confine distribution and notes operands beneath
GITHUB_WORKSPACE - accept a lexical workspace alias while rejecting symlinks inside the
workspace-relative path - require
O_DIRECTORY,O_NOFOLLOW, andO_NONBLOCKinstead of weakening
filesystem checks on unsupported platforms - require exact manifest lines containing 64 lowercase SHA-256 characters, two
spaces, and a confined basename - reject empty manifests, duplicate or self entries, extra or missing files,
symlinks, directories, FIFOs, unreadable files, and digest mismatches - create private
justdocs-release-*roots under a nonsymlinkRUNNER_TEMP - copy assets and optional notes through bound descriptors in 1 MiB chunks,
create files exclusively, flush and fsync bytes, and set copied files to mode
0400 - preserve the literal
SHA256SUMS.txtbytes and record its digest with every
asset and optional notes digest - serialize deterministic
snapshot.jsonmetadata and restrict the asset
directory to mode0500 - verify exact metadata keys, integer snapshot version, root identity, asset
inventory, asset hashes, notes hash, and root inventory - keep staged bytes independent from later source artifact or notes mutation
- clean partial snapshots after setup or copy failures and retain both primary
and cleanup errors when removal fails - constrain cleanup to the named child of the supplied parent, reject symlinks
and special entries, and compare root device and inode before removal - retain
O(B + n log n)staging and verification time withO(n + 1 MiB)
auxiliary state forBbytes andnassets
PyPI reconciliation:
- add typed local-artifact, remote-query, and artifact-mismatch errors
- bind local wheel and source distributions to no-follow descriptors and hash
them in 1 MiB chunks - query percent-encoded package and version endpoints with JSON headers, a
15-second request bound, and a 4 MiB response ceiling - classify HTTP 404 as
absentand reject other HTTP, transport, encoding, JSON,
and response-shape failures explicitly - compare versions through PEP 440 normalization, including equality between
forms such as1.2.3and1.2.3.0 - require unique nonempty remote filenames and exact lowercase SHA-256 metadata
- return deterministic
absent,partial, orexactstates with sorted missing
inventories - reject unexpected remote filenames or mismatched shared-file digests
- stage only missing files into a previously absent destination using exclusive
mode-0400outputs, fsync, byte-count checks, and post-copy hash verification - remove partial staging destinations after failure and report cleanup failure
alongside the primary error - poll with a monotonic deadline, shrinking request bounds, retrying transient
remote failures and incomplete states while propagating artifact mismatches - validate interval and total duration as positive finite values
- delegate
verify-pypi.pyto the exact artifact checker through the active
interpreter and passartifacts/releasefrom the shell wrapper - remove the 21-line
release-artifacts.shpath-only inventory helper
Release workflows:
- validate action inputs and stage immutable bytes before any GitHub mutation
- route action operands through environment variables, log values with
printf %q, and avoid raw workflow expressions inside shell bodies - derive transaction targets from checked-out
HEAD^{commit}instead of the
workflow event SHA - replace force-pushed tags, direct release create/edit, direct asset deletion,
andgh release upload --clobberwith transaction preflight and publication - preserve staging and preflight failures while surfacing cleanup failures
- run final transaction and snapshot cleanup unconditionally and attempt both
removals independently - upgrade checkout to v7, upload-artifact to v7, download-artifact to v8, CodeQL
to v4, and build-provenance attestation to v4 - archive both distribution uploads and reject digest mismatches on all five
distribution downloads - add a CI artifact round trip that downloads
justdocs-python-distand verifies
SHA256SUMS.txt - replace pattern-based merged downloads with exact named
python-dist
retrieval - require a tag for manual stable releases and serialize runs by dispatch tag or
pushed ref name - check out the selected stable tag, validate event type and SHA, and carry the
resolved immutable commit through build and publication - fetch
origin/mainfor latest releases, require checked-out HEAD equality,
and derive full and 12-character release SHAs from the fetched commit - disable latest-run cancellation so an active publication reaches a terminal
transaction phase - inspect PyPI before credential selection, skip uploads for exact existing
artifacts, and stage only missing distributions for absent or partial states - select trusted publishing before API-token authentication and expose
existing,trusted,token, andnonepublication modes - reject unknown PyPI classifications with exit code 2
- provision Python 3.12, exact downloaded artifacts, digest checks, and
packaging>=24in the public PyPI verification job - pass release-note and publication values through environment variables instead
of interpolating expressions into executable shell
Release metadata and platform tooling:
- add shared validators for exact lowercase Booleans, Git-compatible tags,
control-free release names, and canonicalOWNER/REPOSITORYidentities - constrain owners to 1..39 valid characters and repository names to 1..100
valid characters while excluding malformed hyphen and dot forms - replace Bash nameref and
mapfiletag selection with a Bash-3.2-compatible
Python implementation - resolve Python from
PYTHON_BINorpython3, require Python 3.10+, return 127
for a missing executable, and preserve interpreter failures - ignore invalid version tags, order valid tags by PEP 440 plus literal tag, and
select the highest or first strictly lower semantic version - dispatch release metadata by
workflow_dispatchor tagpushand reject
unsupported events or nontag pushes - require fetched tag, checked-out HEAD, and push event SHA to resolve to the
same commit - emit
release_refas the immutable release SHA instead of the mutable tag - wrap PowerShell interpreter resolution in array syntax to preserve one-token
paths and multi-tokenpy -3prefixes - quote the POSIX
profile_kind='sh'assignment - preserve Markdown commit-link backticks through the release-note
printf
format - ignore the complete
TODOS_LISTS/tree and.tmp-workflow-tools/
Security automation:
- group all GitHub Actions dependency changes under one weekly Dependabot group
- replace pull-request-only dependency review with pinned
pip-audit==2.10.1
strict resolved-project auditing across every security workflow trigger - retain Python and Actions CodeQL matrices while upgrading initialization and
analysis to v4
Tests:
- add 26 test methods, including 15 transactional release scenarios
- add a stateful fake GitHub CLI covering GraphQL reads, paginated assets,
commits, comparisons, refs, releases, binary uploads, renames, deletes, and
deterministic failure injection - cover immutable exact no-op and mismatch rejection, malformed operands,
release-query races, nonmonotonic latest movement, and tag compare-and-set
failures - verify absent-release marker creation, payloads, target SHA, temporary upload
naming, MIME types, digests, journal contents, and final publication - cover create failure, post-create query failure, external marker replacement,
retained-target-tag retry, purge and preserve modes, and exact mutation order - inject failures after retained deletes and publish patches plus process death
after tag movement, partial deletion, partial upload, and final publication - prove commit-forward convergence after irreversible boundaries and rollback
before those boundaries - verify starter cleanup, asset-ID preservation, unknown concurrent-asset
preservation, successful committing-phase reconciliation, and interrupted
cleanup recovery - execute composite-action cleanup against real transaction and snapshot roots
and require an empty runner temporary directory - cover one valid action input set and 22 fail-closed Boolean, tag, path,
permission, directory, FIFO, and symlink cases - cover workspace aliases, internal symlinks, source mutation independence,
asset and notes tampering, malformed metadata, extra inventories, cleanup
boundaries, partial cleanup failure, and setup failure residue - classify absent, exact, normalized, partial, mismatched, transient, and HTTP
500 PyPI responses and verify missing-only staging - assert shrinking PyPI request bounds of 9, 7, and 5 seconds
- cover Bash 3.2 source constraints, PEP 440 alias ordering, interpreter exit
propagation, and missing-interpreter exit 127 - require resolved force-overwrite project paths and reject user-site prefix
collisions when selecting pip scope - assert PowerShell array initialization and complete configured-interpreter
dry-run output - extend workflow contracts for transaction ordering, checked-out commit
targeting, expression confinement, action versions, artifact names, digest
gates, and helper removal
Checks:
git diff --cached --check: pass, no outputbash -n install.sh scripts/release/github-repository.sh scripts/release/release-versioning.sh scripts/release/resolve-release-metadata.sh scripts/release/verify-pypi.sh scripts/release/write-release-notes.sh: passPYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tests: 100 tests
run in 46.167 seconds, 1 failure in
test_release_pipeline_uses_dist_action_pypi_publish_and_release_assets- the failing staged counter expects setup-python 7, download-artifact 4, and
dependency-review v5 once; staged workflows contain setup-python 9,
download-artifact 5, and no dependency-review action - later staged assertions also expect four digest gates, four
python-dist
names, and the prior concurrency expression; staged workflows contain five
digest gates, five names, and event-aware tag concurrency
Measurements:
- staged index: 21 files changed, 7,060 insertions, 330 deletions
- major additions: 2,259-line transaction engine, 533-line snapshot engine,
380-line PyPI reconciler, and 3,429 added test lines
- add
add19aefix: harden cross-platform release filesystem boundariesMake PyPI artifact binding native on Windows and canonicalize trusted POSIX
system aliases without weakening descriptor-relative confinement. Rework
snapshot and transaction boundaries around canonical parents, then replace
brittle global workflow counts with source-local and step-local contracts.Windows artifact binding:
- add conditional ctypes bindings for CreateFileW, GetFileInformationByHandle,
GetFileInformationByHandleEx, GetFileType, and CloseHandle - model stable identity as a 64-bit volume serial plus 128-bit file ID
- capture handle attributes, 64-bit size, and 64-bit last-write time
- open every ancestor from the filesystem root through the artifact directory
before inventory enumeration - retain ancestor handles with read/write sharing but no delete sharing
- open artifact files with read-only sharing to deny concurrent writes,
deletion, and renaming - inspect reparse points directly with FILE_FLAG_OPEN_REPARSE_POINT
- reject non-disk handles, reparse points, and directory/file type mismatches
- transfer native file handles into noninheritable binary CRT descriptors
without double-closing ownership - hash retained descriptors and reject identity, attribute, size, or write-time
changes after reading - rescan the distribution directory and require exact ordered inventory
equality after artifact binding - recheck every ancestor identity and leaf-directory state before exposing
bound artifacts - close artifact descriptors before directory handles and release ancestors in
reverse acquisition order - preserve Win32 failures through use_last_error and typed PyPIArtifactError
translation
Cross-platform artifact inventory:
- centralize wheel and sdist enumeration for path-based and descriptor-based
directory scans - accept only .whl and .tar.gz regular files
- reject symlink entries, nonregular entries, empty inventories, and duplicate
names - return immutable lexicographically sorted artifact names
- preserve O_DIRECTORY, O_NOFOLLOW, O_NONBLOCK, and dir_fd confinement on
POSIX - dispatch transparently between native Windows and existing POSIX binders
through the unchanged _open_local_artifacts contract
Secure POSIX paths:
- add SecurePathError and shared O_RDONLY | O_DIRECTORY | O_NOFOLLOW flag
validation - open absolute directories component-by-component relative to the preceding
descriptor - reject nonabsolute paths, explicit parent traversal, missing flags, and
descendant symlinks - permit only first-component system aliases owned by UID 0 beneath a UID-0,
non-group-writable, non-world-writable filesystem root - bind trusted aliases through device, inode, mode, owner, size, mtime, and
ctime identity - compare alias identity before and after readlink, securely open the canonical
target, then verify the original alias again - normalize absolute and relative alias targets before appending remaining path
components - canonicalize child parents while preserving final basenames for later
descriptor-relative no-follow opens - replace duplicated path traversal in snapshot and transaction engines with
domain-specific error translation wrappers
Snapshot lifecycle:
- map workspace-relative operands directly beneath the resolved workspace after
per-component symlink checks - canonicalize absolute RUNNER_TEMP paths while retaining final-component
symlink rejection - accept root-owned system aliases such as macOS /var to /private/var without
admitting nested writable aliases - verify each mkdtemp result remains an immediate child of the canonical stage
parent before writing snapshot data - pass canonical parent and root identities explicitly into partial-failure
cleanup - reject cleanup when the created root does not belong to the supplied
canonical parent - canonicalize snapshot parents during verify and cleanup while retaining
prefix, inventory, digest, permission, device, and inode checks - preserve snapshot schema version 2 and existing manifest semantics
Transaction boundaries:
- canonicalize transaction parents through the shared secure POSIX path layer
- report invalid parents as expected secure directories
- verify each preflight transaction root remains beneath its canonical parent
before journal creation - canonicalize caller-supplied transaction-root parents before descriptor-bound
journal loading - require persisted parent metadata to be absolute, abspath-normalized, securely
canonical, and already stored in canonical spelling - reject transaction roots whose parent differs from canonical journal metadata
- canonicalize staged distribution directories without unrestricted
resolve(strict=True) traversal - require staged distributions to remain the verified assets directory
- canonicalize release-note parents while requiring the exact
release-notes.md child - preserve transaction schema version 4, release state transitions, GitHub
mutation ordering, and recovery semantics
Workflow contract tests:
- replace one repository-wide action Counter with exact per-source action sets
- require 5 CI, 5 Latest, 7 Release, 3 reusable-build, 4 Security, 1
build-composite, and 0 release-composite unique action references - parse individual six-space-indented workflow steps instead of comparing
offsettable global text counts - require every download-artifact v8 step to set digest-mismatch: error
- require justdocs-python-dist for CI transfers and python-dist for Latest and
Release transfers - require every upload-artifact v7 step to set archive: true
- require justdocs-python-dist for CI uploads and python-dist for reusable
build uploads - require pip-audit==2.10.1 with strict resolved-project auditing
- require removal of dependency-review-action from the Security contract
- require manual releases to group by inputs.tag and other release events by
github.ref_name - require cancel-in-progress: false for Release and Latest publication groups
Platform regression tests:
- reject a directory named invalid.whl as malformed local inventory before any
PyPI request - require Windows-bound wheels to reject concurrent overwrite and rename
attempts - prove Windows file handles release after leaving the binding context
- create a Windows directory junction with mklink /J and reject it before any
PyPI request - discover trusted root aliases from /var, /tmp, /bin, /sbin, and /lib
- require trusted UID-0 aliases to resolve to their absolute targets
- reject temporary user-owned directory aliases with SecurePathError
- increase the test-method inventory from 100 to 101
Complexity:
- retain Windows binding time O(d + e + B) for path depth d, directory entries
e, and aggregate artifact bytes B - retain Windows auxiliary state O(d + n + 1 MiB) with d ancestor handles and
n artifact descriptors - retain POSIX artifact time O(e + B) and state O(n + 1 MiB)
- bound secure POSIX canonical traversal to O(d) opens and O(1) live traversal
descriptors
Checks:
- git diff --cached --check: pass with no output
- PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=. python3 -m unittest discover -s tests:
101 tests pass on Linux in 43.936 seconds - Ruff check: pass
- Ruff format check: 5 changed Python files formatted
- Actionlint 1.7.12: pass for all GitHub workflows
- ShellCheck 0.11.0: pass for installer and release shell scripts
- SOURCE_DATE_EPOCH=0 PYTHONHASHSEED=0 just dist: wheel and sdist build
- SHA256SUMS.txt verification: pass for every release artifact
- Twine 6.2.0: wheel and sdist metadata pass
- read-only latest preflight against FanaticPythoner/justdocs at
2493c0c: pass with local journal cleanup - hosted Windows and macOS reruns are not claimed by local evidence
Measurements:
- staged index: 5 files changed, 862 insertions, 232 deletions
- new secure POSIX helper: 163 lines
- POSIX 2 MiB artifact-binding benchmark, 400 alternating samples:
baseline p50 2.6244 ms, p95 3.3116 ms, 762.1 MiB/s - repaired POSIX binding: p50 2.6133 ms, p95 3.3126 ms, 765.3 MiB/s
- baseline and repaired peak RSS: 22,348 KiB
- add conditional ctypes bindings for CreateFileW, GetFileInformationByHandle,
35949a6feat: harden release transactions and recover detached latest releasesStrengthens release publication, rollback, filesystem confinement, and legacy
latest-release recovery across the staged release pipeline.Release transaction recovery:
- Persist transaction version 6 journals with root identity, creation-attempt
state, pre-create release inventory, owned asset IDs, and phase invariants. - Serialize transaction access with an exclusive descriptor lock.
- Verify transaction root device and inode identity before journal reads,
mutations, recovery, and cleanup. - Recover release creation failures by identifying exactly one post-baseline
draft marked with the transaction identity. - Preserve externally modified or published releases when rollback ownership is
indeterminate. - Reconcile tagging and committing phases forward when the publish mutation
already succeeded. - Restore original release metadata, tag ownership, asset names, asset IDs,
and observable asset contents with post-mutation verification. - Detect lost journals, detached transaction releases, marker releases, and
reserved transaction assets before further GitHub mutations. - Reject pre-existing draft releases, incomplete uploads, concurrent release
changes, tag ownership changes, and non-monotonic tag movement. - Reserve
justdocs-rollback-*andjustdocs-upload-*asset names against
staged and pre-existing release assets. - Use exclusive descriptor-relative JSON writes with explicit regular-file
validation and durable flushes. - Require transaction cleanup to authenticate the original root identity,
recover active phases, and remove only terminal transaction trees.
GitHub transport and API verification:
- Require curl 7.76.0 or newer and readable
/dev/fddescriptor semantics
during preflight. - Construct authorization headers through a pipe-backed descriptor and remove
GH_TOKENandGITHUB_TOKENfrom the curl child environment. - Supply exact content lengths for authenticated upload and JSON requests.
- Reject unsafe authorization tokens, malformed curl commands, invalid response
encodings, missing executables, and non-regular transaction inputs. - Parse release metadata with strict type, identity, asset-name, digest, and
pagination checks. - Query release metadata and assets around stable before-and-after snapshots to
detect concurrent GitHub mutations. - Verify release creation responses contain the expected draft marker, target
commit, prerelease state, and empty asset set.
Detached latest recovery:
- Add
recover-detached latestfor the
FanaticPythoner/justdocsrepository only. - Identify detached GitHub Actions releases through exact tag, author, name,
description, target-commit, prerelease, draft, and five-asset invariants. - Stream and verify detached asset bytes against GitHub-provided size and
SHA-256 metadata. - Parse the four-entry
SHA256SUMS.txtmanifest and map each digest to its
installer, wheel, and source distribution. - Rename assets through deterministic rollback names, persist progress through
each boundary, and verify every rename before continuing. - Rebind the recovered release to
latest, publish it as prerelease, and
verify final release, tag, asset, and residue invariants. - Treat already-bound releases as idempotent no-ops while still scanning for
detached transaction residue. - Reject malformed manifests, duplicate candidates, altered asset metadata,
changed tags, unexpected detached refs, invalid authors, and ambiguous
recovery states.
Secure snapshot staging:
- Introduce
BoundCreatedDirectorybindings containing parent descriptor,
directory descriptor, device, and inode identity. - Bind newly created snapshot roots to the expected parent and required
justdocs-release-prefix before population or cleanup. - Perform asset, manifest, metadata, and notes writes relative to retained
directory descriptors withO_NOFOLLOW, exclusive creation, mode
hardening, andfsync. - Verify directory-entry identity after opening, staging, recursive cleanup,
and before root removal. - Detect nested directory substitution, snapshot-root replacement, inventory
tampering, and cleanup races. - Centralize the snapshot prefix and retain snapshot metadata version 2.
Workflow coordination:
- Serialize release mutation jobs per repository in
latest.ymland
release.ymlwith non-canceling queued concurrency. - Run detached latest recovery before latest-release preflight.
Tests and fixtures:
- Extend the transactional GitHub fixture with REST and GraphQL-like metadata,
pagination, asset streaming, tag races, release races, crash injection,
partial uploads, external mutation, and transport-failure scenarios. - Cover absent-release creation, existing-release replacement, immutable-release
no-op and mismatch handling, rollback, commit-forward recovery, cleanup
recovery, retained assets, asset-ID preservation, and residue detection. - Cover every detached latest recovery boundary, terminal convergence,
idempotent execution, invalid profiles, duplicate candidates, transport
validation, and repository/tag scoping. - Cover secure descriptor binding, symlink boundaries, inventory tampering,
nested substitution, partial cleanup failure, and setup failure cleanup. - Preserve exact mutation assertions ensuring unknown-length standard-input
mutations are rejected.
Checks:
git diff --cached --checkexits cleanly.python3 -m unittest tests.test_package -k releasepasses 44 tests in
72.112 seconds.- Six targeted secure snapshot and path-boundary tests pass in 1.407 seconds.
Measurements:
- Staged index: 7 modified files, 3,874 insertions, 391 deletions.
- Persist transaction version 6 journals with root identity, creation-attempt
2b18875macos fix7b16366feat(release): automate verified Python package publicationRelease preparation:
- Add
just next-releasewith patch, minor, and major SemVer increments. - Require a clean default branch synchronized with its remote before release preparation.
- Generate dated changelog entries from the Unreleased section and chronological NUL-delimited Git records.
- Atomically replace version and changelog files with preserved modes, file fsync, directory fsync, and symlink rejection.
- Create the version commit and annotated tag locally; require
--pushfor an atomic branch-and-tag push. - Generate stable release notes from the resulting immutable tag boundary.
Publication:
- Default PyPI publication to OIDC trusted publishing when no API token is configured.
- Retain
PYPI_API_TOKENas an explicit authenticated publication path. - Remove the repository-variable gate and the silent no-publication mode.
- Require PyPI completion before GitHub Release creation.
- Verify the public GitHub release tag target, title, notes, draft state, prerelease state, latest-release binding, asset inventory, byte lengths, and SHA-256 digests.
- Resolve annotated tag chains through at most eight validated Git objects.
- Bound GitHub REST responses to 2 MiB and reject malformed identities, JSON, tags, metadata, and local artifact paths.
PR distributions:
- Retain CI distribution artifacts for 90 days with overwrite semantics.
- Add a trusted
workflow_runpublisher with minimal read and pull-request write permissions. - Check out only the default-branch implementation with persisted credentials disabled.
- Validate the completed CI run identity, pull-request binding, commit SHA, artifact uniqueness, expiry, byte length, and SHA-256 digest.
- Create or replace exactly one marker-bound
github-actions[bot]comment. - Publish artifact, workflow, expiry, digest, and isolated-install security metadata without executing pull-request code under write permissions.
- Bound API responses to 4 MiB and comment traversal to 10,000 entries.
Supply chain:
- Pin checkout, Python setup, artifact upload and download, PyPI publication, provenance attestation, and CodeQL actions to immutable 40-hex revisions.
- Preserve human-readable action release annotations beside each pinned revision.
- Extend workflow contract tests to reject every unpinned external action reference.
- Verify downloaded artifact digests and retain provenance attestation for wheel, source archive, installers, and checksum manifest.
Packaging and documentation:
- Add persistent release history in
CHANGELOG.md. - Include changelog, license, and README files in source distributions through
MANIFEST.in. - Expose the changelog through package project metadata.
- Replace Bash
mapfileusage with a portable NUL-delimited read loop. - Document trusted-publisher identity, token fallback, release commands, publication invariants, PR artifacts, and public digest verification.
- Synchronize release guidance across the README and bundled example documentation.
Tests:
- Add an isolated Git repository test covering initial changelog generation, release commit creation, annotated tagging, release-note generation, and no implicit remote tag publication.
- Add PR comment tests covering rendered artifact metadata, workflow-event binding, artifact selection, bot ownership, and spoofed user-comment rejection.
- Add exact local-to-remote GitHub asset size and SHA-256 equivalence coverage.
- Expand packaging and workflow assertions for pinned actions, trusted publication defaults, artifact retention, release verification, manifest contents, and documentation surfaces.
Checks:
PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=. python3 -m unittest discover -s tests: 124 tests passed in 134.462 seconds.SOURCE_DATE_EPOCH=0 PYTHONHASHSEED=0 just dist: wheel and source distribution built; Twine checks passed.- Two deterministic builds produced byte-identical wheel, source archive, installers, and checksum manifest.
- Isolated wheel installation, project initialization, project checking, and strict documentation build passed.
- Ruff checking, Ruff formatting verification, Python byte-compilation, and 33 ShellCheck Bash-block checks passed.
- Actionlint reported two schema diagnostics for the GitHub-supported
queue: maxexpression and no other diagnostics. git diff --cached --checkreportsCHANGELOG.md:16: new blank line at EOF.
Measurements:
- Staged scope: 19 files, 1,531 insertions, 76 deletions.
- File topology: 6 additions and 13 modifications.
- Test topology: 405 insertions and 27 deletions in the package contract suite.
- Test inventory: 124 test methods.
- Release assets verified across 5 byte-identical outputs.
- Add
4b579aarelease: v0.1.0