Release conditions
RequestSeal is Elixir only. The TypeScript counterpart and npm package are deferred, not planned for the current release. Cross-language parity is outside current release acceptance.
Release acceptance must establish the advertised scope through the actual public entry points, package artifact, documentation, and required counterpart checks. The current checkout implements generic RFC 9421 signing, single-label and quorum verification, caller-owned custody, discovery, nonce replay, optional Req/Finch and Plug/Phoenix adapters, Ash scope mapping, generic compact JWS/JWE, one-level JWS-in-JWE nesting, and source-selected Web Bot Auth protocol-00 signing and identity attribution. Other named application profiles belong in extension packages.
Set the package version in
mix.exsto0.2.0, update every install to{:request_seal, "~> 0.2.0"}, and record the release inCHANGELOG.md. Confirm the public document allowlist, supported profiles, and accepted ADRs.Use Elixir 1.20.4 / OTP 29.1.1, the exact development pins. Run focused checks while editing, then run the declared gate once on the final source:
python3 scripts/check.pyThe gate checks examples, notebooks against the real checkout, generated docs, dependency advisories, and optional integration metadata. Local notebook execution substitutes the checkout for the validated Hex install cell; it does not prove registry delivery. Inspect generated docs in a browser separately.
Release builds and publishing require Elixir 1.20 or newer. The
hex.publishalias refuses publishing below 1.20 before invoking Hex; older toolchains omit optional integrations from development dependencies. Run the same guard before building the release artifact:mix run --no-start -e 'check = Mix.Project.config()[:aliases][:"hex.publish"] |> hd(); check.([])' && mix hex.buildInspect
contents.tar.gzinsiderequest_seal-0.2.0.tar. Its files must be onlylib/**/*.ex,mix.exs, and the public documents explicitly allowlisted inmix.exs, including README, CHANGELOG, LICENSE, and NOTICE. Exclude tests, scripts, local credentials, internal records, and key fixtures. Record the list locally and delete the inspected tarball. Inspecthex_metadata.configfrommix hex.build --unpack: bothash_onetimeandash_hooksmust be optional requirements. The latest CI lane checks and deletes its unpacked artifact.Commit the final source and push the release commit. Wait for CI on that exact commit to pass all three Linux lanes: floor Elixir 1.18.4 / OTP 27.3.4, mid Elixir 1.19.5 / OTP 28.5.0.7, and latest Elixir 1.20.4 / OTP 29.1.1. The floor lane checks optional client floors; latest runs the full declared gate and the Elixir 1.20 optional integrations.
git push origin HEAD gh run list --workflow ci.yml --commit "$(git rev-parse HEAD)" gh run watch RUN_ID --exit-statusBefore changing visibility, scan the full history of every branch and tag, including commit messages. Use a nonempty literal private-term list kept outside public source, referenced by
RELEASE_PRIVATE_TERMS_FILE. Keep scan output local; resolve every match before proceeding. Fetch complete history first:set -eu set -o pipefail : "${RELEASE_PRIVATE_TERMS_FILE:?Set the private-term file path}" test -s "$RELEASE_PRIVATE_TERMS_FILE" rg --quiet --fixed-strings --ignore-case --file "$RELEASE_PRIVATE_TERMS_FILE" "$RELEASE_PRIVATE_TERMS_FILE" if test "$(git rev-parse --is-shallow-repository)" = true; then git fetch --unshallow origin fi git fetch --all --tags mkdir -p .kimosabe git rev-list --all > .kimosabe/release-history-commits.txt test -s .kimosabe/release-history-commits.txt : > .kimosabe/release-history-matches.txt while IFS= read -r revision; do if git grep --line-number --ignore-case --fixed-strings --file "$RELEASE_PRIVATE_TERMS_FILE" "$revision" >> .kimosabe/release-history-matches.txt; then : else result=$? test "$result" -eq 1 || exit "$result" fi done < .kimosabe/release-history-commits.txt if git log --all --format='%H %B' | rg --line-number --ignore-case --fixed-strings --file "$RELEASE_PRIVATE_TERMS_FILE" >> .kimosabe/release-history-matches.txt; then : else result=$? test "$result" -eq 1 || exit "$result" fi test ! -s .kimosabe/release-history-matches.txtThis scans all fetched history, including deleted file contents. The term-file self-match is the scanner's positive control. An empty result establishes only that the configured terms were not found; inspect package/source disclosure too.
Make GitHub public and publish Hex 0.2.0 in the same release event. From the pinned Elixir 1.20 checkout, load
HEX_API_KEYfrom the project's gitignored.env; refer to the key by name and never print its value. Verify the security reporting channel and package ownership, then run:set -a . ./.env set +a : "${HEX_API_KEY:?Set HEX_API_KEY in the project .env}" gh repo edit baselabs/request_seal --visibility public --accept-visibility-change-consequences mix hex.publish --yes gh repo view baselabs/request_seal --json visibility --jq .visibility mix hex.info request_seal 0.2.0 curl --fail --location --silent --show-error --output /dev/null https://hexdocs.pm/request_seal/0.2.0/index.htmlConfirm GitHub reports
PUBLIC, Hex reports version 0.2.0, and HexDocs 0.2.0 serves the expected guides and source links. Inspect actual registry checksums and optional metadata.Install from Hex in a clean consumer, without a path or Git override. Use an empty Mix install directory and verify the installed application version and an actual public entry point:
consumer_dir=$(mktemp -d) trap 'rm -rf "$consumer_dir"' EXIT MIX_INSTALL_DIR="$consumer_dir" elixir -e ' Mix.install([{:request_seal, "~> 0.2.0"}]) "0.2.0" = Application.spec(:request_seal, :vsn) |> to_string() {:ok, message} = RequestSeal.Message.request("GET", "https://example.com/", [], nil) "GET" = message.method IO.puts("PASS: Hex 0.2.0 clean-consumer install and request construction") 'Repeat the documented signing/verifying journey in that consumer. Record the exact source commit, CI result, artifact checksum, public visibility, HexDocs, and clean-consumer output locally. Local checks do not establish hosted CI, provider acceptance, or registry delivery.
Dependency updates
The root uses ExDoc for development and tests, SimpleSat for tests, and optional Ash,
Req, Finch, and Postgrex dependencies. Livebook lives in tools/notebooks with a
separate lockfile. It pins application dependencies that may need explicit security overrides;
each override has a reason in its Mix file and must pass the real importer/exporter checks.
Review mix hex.outdated in both environments and run mix hex.audit after any change.
Toolchain or major dependency changes invalidate task-owned build artifacts and analysis caches;
perform one clean rebuild on the final dependency set and preserve evidence.
Incident and rollback
First stop use of the affected profile or artifact in caller policy while preserving evidence. Record affected revisions, algorithms, identity/key scope and actual exposure. Coordinate a patched release and necessary key revocation/replay-store response. A package retirement does not erase cached artifacts: publish an advisory and upgrade guidance through verified channels. Use the registry's documented retirement command only with explicit authority; do not guess automatic rollback semantics. Changing an installed application's dependency is its owner's act.