Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.4.12] - 2026-09-17

### Changed

- **Release trust anchors rotated to the current organization keys.** Within
the bootstrap engine and installer's supported v0.4.9–v0.4.12 pin range,
v0.4.12 selects only the new minisign and OpenPGP anchors. Pins through
v0.4.11 select only the previous anchors; these install paths never fall
back between keys.
- **Go and module refresh.** The module now declares Go 1.26.0 with the Go
1.26.8 toolchain, jsonschema/v6 6.0.3, and current `x/crypto`, `x/sys`, and
`x/text` releases.
- **CI and security tooling refreshed.** Goneat moves to v0.6.0,
govulncheck to v1.8.0, and GitHub Actions use immutable commit pins.

### Fixed

- **Security-scanner compatibility for archive extraction.** Scoped G703
dispositions document the existing path-containment checks at filesystem
sinks while the zip-slip rejection tests continue to enforce the boundary.

## [0.4.11] - 2026-07-31

### Added
Expand Down Expand Up @@ -183,7 +204,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

> **Maintenance note:** This file is pruned to the latest 10 releases. For older entries, see `docs/releases/`.

[Unreleased]: https://github.com/3leaps/sfetch/compare/v0.4.10...HEAD
[Unreleased]: https://github.com/3leaps/sfetch/compare/v0.4.12...HEAD
[0.4.12]: https://github.com/3leaps/sfetch/compare/v0.4.11...v0.4.12
[0.4.11]: https://github.com/3leaps/sfetch/compare/v0.4.10...v0.4.11
[0.4.10]: https://github.com/3leaps/sfetch/compare/v0.4.9...v0.4.10
[0.4.9]: https://github.com/3leaps/sfetch/compare/v0.4.8...v0.4.9
[0.4.8]: https://github.com/3leaps/sfetch/compare/v0.4.7...v0.4.8
Expand Down
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,22 +214,22 @@ Match `-P` to the tag: tags ≤ v0.4.11 verify under the previous key; newer tag

```bash
# Three-step path when install-sfetch.sh.minisig is published (v0.4.11+)
TAG=v0.4.11
TAG=v0.4.12
curl -fsSL "https://github.com/3leaps/sfetch/releases/download/${TAG}/install-sfetch.sh" -o install-sfetch.sh
curl -fsSL "https://github.com/3leaps/sfetch/releases/download/${TAG}/install-sfetch.sh.minisig" -o install-sfetch.sh.minisig
minisign -Vm install-sfetch.sh -P RWTAoUJ007VE3h8tbHlBCyk2+y0nn7kyA4QP34LTzdtk8M6A2sryQtZC
minisign -Vm install-sfetch.sh -P RWTqUZ/PtmfAbQ3RKIlp/YTKT6zFeNMAZ8iAMelhlmqEsVqjKj3ctSA1
bash install-sfetch.sh --tag "$TAG" --yes

# Or use the shared engine (CI/Makefile; refuses "latest"):
# ./scripts/bootstrap-sfetch-verified.sh --version v0.4.11 --dir ~/.local/bin
# ./scripts/bootstrap-sfetch-verified.sh --version v0.4.12 --dir ~/.local/bin
```

**GitHub Actions:** pin the composite action by commit SHA — see [CI/CD Usage Guide](docs/cicd-usage-guide.md).

```yaml
- uses: 3leaps/sfetch/.github/actions/setup-sfetch@<commit-sha>
with:
sfetch-version: v0.4.11
sfetch-version: v0.4.12
```

#### Quick install (interactive humans)
Expand All @@ -254,7 +254,7 @@ Pass arguments using `bash -s --`:
curl -sSfL .../install-sfetch.sh | bash -s -- --dir ~/bin

# Install specific version
curl -sSfL .../install-sfetch.sh | bash -s -- --tag v0.4.11
curl -sSfL .../install-sfetch.sh | bash -s -- --tag v0.4.12

# Dry run (download and verify, don't install)
curl -sSfL .../install-sfetch.sh | bash -s -- --dry-run
Expand Down Expand Up @@ -302,13 +302,13 @@ Tag CI creates a **draft** release with unsigned archives. Maintainers generate
export SFETCH_MINISIGN_KEY=/path/to/sfetch.key
export SFETCH_PGP_KEY_ID=security@fulmenhq.dev # optional

RELEASE_TAG=v0.4.11 make release-download
RELEASE_TAG=v0.4.11 make release-checksums
RELEASE_TAG=v0.4.11 make release-sign # signs manifests + install-sfetch.sh
RELEASE_TAG=v0.4.12 make release-download
RELEASE_TAG=v0.4.12 make release-checksums
RELEASE_TAG=v0.4.12 make release-sign # signs manifests + install-sfetch.sh
make release-verify
RELEASE_TAG=v0.4.11 make release-notes
RELEASE_TAG=v0.4.11 make release-upload
gh release edit v0.4.11 --draft=false # publish only after signatures upload
RELEASE_TAG=v0.4.12 make release-notes
RELEASE_TAG=v0.4.12 make release-upload
gh release edit v0.4.12 --draft=false # publish only after signatures upload
```

Set `RELEASE_TAG` to the tag you're publishing. The scripts in `scripts/` can be used individually if you prefer manual control.
Expand Down
46 changes: 46 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,49 @@
## v0.4.12

### Summary

Supply-chain maintenance release with refreshed Go dependencies and immutable
CI action pins. It also completes the release-key rotation for verified
installation: within the bootstrap engine and installer's supported
v0.4.9–v0.4.12 range, v0.4.12 selects only the current organization keys while
pins through v0.4.11 select only the previous keys, without fallback.

### Highlights

**Trust anchors**
- The embedded minisign key and installer OpenPGP fingerprint now match the
current organization release-signing keys.
- For supported bootstrap and installer pins, exactly one key generation is
selected: v0.4.9–v0.4.11 use the previous keys; v0.4.12 uses the current
keys. Releases are not dual-signed and these install paths do not fall back
between anchors.

**Toolchain and dependencies**
- Go module baseline 1.26.0 with toolchain 1.26.8.
- jsonschema/v6 6.0.3 plus refreshed `x/crypto`, `x/sys`, and `x/text` modules.
- Goneat v0.6.0 and govulncheck v1.8.0.

**CI and security checks**
- GitHub Actions are pinned to immutable commit SHAs.
- Archive-extraction G703 dispositions are scoped to sinks already protected
by path-containment checks and zip-slip rejection tests.

### Install

Use the verified bootstrap engine with an exact tag:

```bash
./scripts/bootstrap-sfetch-verified.sh --version v0.4.12 --dir "$HOME/.local/bin"
```

The action revision and `sfetch-version` pin are coupled: consumers advancing
to v0.4.12 must also select an action revision whose declared range includes
v0.4.12. Outside a checkout, retrieve the bootstrap engine at an immutable
revision and verify its pinned digest before execution; see the
[CI/CD Usage Guide](docs/cicd-usage-guide.md).

---

## v0.4.10

### Summary
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.4.11
0.4.12
47 changes: 47 additions & 0 deletions docs/releases/v0.4.12.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# sfetch v0.4.12

Supply-chain maintenance and release trust-anchor rotation.

## Highlights

### Trust anchors

- The embedded minisign key and installer OpenPGP fingerprint now match the
current organization release-signing keys.
- For bootstrap engine and installer pins in the supported v0.4.9–v0.4.12
range, exactly one key generation is selected: v0.4.9–v0.4.11 use the
previous keys; v0.4.12 uses the current keys. Releases are not dual-signed
and these install paths do not fall back between anchors.

### Toolchain and dependencies

- Go module baseline 1.26.0 with toolchain 1.26.8.
- jsonschema/v6 6.0.3 plus refreshed `x/crypto`, `x/sys`, and `x/text` modules.
- Goneat v0.6.0 and govulncheck v1.8.0.

### CI and security checks

- GitHub Actions are pinned to immutable commit SHAs.
- Archive-extraction G703 dispositions are scoped to sinks already protected
by path-containment checks and zip-slip rejection tests.

## Verified bootstrap

Use the release's bootstrap engine with an exact tag:

```bash
./scripts/bootstrap-sfetch-verified.sh --version v0.4.12 --dir "$HOME/.local/bin"
```

The action revision and `sfetch-version` pin are coupled: consumers advancing
to v0.4.12 must also select an action revision whose declared range includes
v0.4.12. Outside a checkout, retrieve the bootstrap engine at an immutable
revision and verify its pinned digest before execution; see the
[CI/CD Usage Guide](../cicd-usage-guide.md).

## Compatibility

There are no CLI or configuration contract changes. The key-selection statement
above applies to the bootstrap engine and installer within their declared
supported pin range; it does not change the CLI's general verification
contract.
12 changes: 6 additions & 6 deletions docs/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,15 +140,15 @@ export SFETCH_MINISIGN_KEY=/path/to/key.key
export SFETCH_MINISIGN_PUB=/path/to/key.pub
export SFETCH_PGP_KEY_ID=your-key-id # optional

RELEASE_TAG=v0.4.11 make release-download
RELEASE_TAG=v0.4.11 make release-checksums
RELEASE_TAG=v0.4.11 make release-sign
RELEASE_TAG=v0.4.12 make release-download
RELEASE_TAG=v0.4.12 make release-checksums
RELEASE_TAG=v0.4.12 make release-sign
make release-verify-signatures
make release-export-keys
make release-verify-keys
RELEASE_TAG=v0.4.11 make release-notes
RELEASE_TAG=v0.4.11 make release-upload
gh release edit v0.4.11 --draft=false
RELEASE_TAG=v0.4.12 make release-notes
RELEASE_TAG=v0.4.12 make release-upload
gh release edit v0.4.12 --draft=false
```

### What is signed (v0.4.11+)
Expand Down
2 changes: 1 addition & 1 deletion scripts/bootstrap-sfetch-verified.sh
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ set -euo pipefail
# make test-bootstrap-range-release asserts MAX == v$(cat VERSION) using two
# committed values at the same SHA (never self-advancing at install time).
readonly SFETCH_BOOTSTRAP_MIN="v0.4.9"
readonly SFETCH_BOOTSTRAP_MAX="v0.4.11"
readonly SFETCH_BOOTSTRAP_MAX="v0.4.12"
# First release that publishes install-sfetch.sh.minisig (route selection).
# Keep this accurate: too low → minisig route without asset; too high → 5-step
# when 3-step exists. Both routes verify; neither silently falls back.
Expand Down
8 changes: 3 additions & 5 deletions scripts/test-bootstrap-sfetch-verified.sh
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ if "$SCRIPT" --version latest --dir /tmp 2>/dev/null; then fail "latest should f
if "$SCRIPT" --version main --dir /tmp 2>/dev/null; then fail "main should fail"; else pass "rejects main"; fi
if "$SCRIPT" --version v0.4.11-rc1 --dir /tmp 2>/dev/null; then fail "prerelease should fail"; else pass "rejects prerelease"; fi
if "$SCRIPT" --version v0.4.8 --dir /tmp 2>/dev/null; then fail "below min should fail"; else pass "rejects below min"; fi
if "$SCRIPT" --version v0.4.12 --dir /tmp 2>/dev/null; then fail "above max should fail"; else pass "rejects above max"; fi
if "$SCRIPT" --version v0.4.13 --dir /tmp 2>/dev/null; then fail "above max should fail"; else pass "rejects above max"; fi
# F2: leading-zero components must not pass range/route selection
if "$SCRIPT" --version v0.4.09 --dir /tmp 2>/dev/null; then fail "v0.4.09 leading zero should fail"; else pass "rejects v0.4.09 leading zero"; fi
if "$SCRIPT" --version v0.04.11 --dir /tmp 2>/dev/null; then fail "v0.04.11 leading zero should fail"; else pass "rejects v0.04.11 leading zero"; fi
Expand Down Expand Up @@ -337,17 +337,15 @@ grep -Eq 'anchor=legacy' "$OUT_CURONLY" || fail "expected anchor=legacy selectio
if grep -q '^route=' "$OUT_CURONLY"; then fail "failed run must not emit machine route="; fi
pass "old pin ignores current anchor (no fallback)"

# Post-cutover selection: fake v0.4.12 pin (MAX patched in temp copy only).
# Post-cutover selection: v0.4.12 is in the production engine's supported range.
# Stand-in keys prove the rule: new pins use current, previous-key sigs fail.
NEWENG="$WORKDIR/newpin-engine.sh"
make_fixture_engine "$NEWENG" "$BASE" "$OLD_EPHEMERAL_PUBKEY" "SFETCH_MINISIGN_PUBKEY_LEGACY"
sed -i.bak "s|${PROD_PUBKEY}|${NEW_EPHEMERAL_PUBKEY}|g" "$NEWENG"
grep -q "$NEW_EPHEMERAL_PUBKEY" "$NEWENG" || fail "new-pin engine missing current stand-in"
grep -q "$PROD_PUBKEY" "$NEWENG" && fail "new-pin engine still has production current key"
grep -q "$OLD_EPHEMERAL_PUBKEY" "$NEWENG" || fail "new-pin engine lost legacy stand-in"
sed -i.bak 's|SFETCH_BOOTSTRAP_MAX="v0.4.11"|SFETCH_BOOTSTRAP_MAX="v0.4.12"|' "$NEWENG"
grep -q 'SFETCH_BOOTSTRAP_MAX="v0.4.12"' "$NEWENG" || fail "new-pin engine MAX patch failed"
rm -f "${NEWENG}.bak"
grep -q 'SFETCH_BOOTSTRAP_MAX="v0.4.12"' "$NEWENG" || fail "new-pin engine MAX drifted"

# Positive: post-cutover pin verifies against the current anchor.
minisign -S -s "$NEWKEY" -t "test-v0.4.12-new" -m "$SRV_ROOT/v0.4.12/install-sfetch.sh"
Expand Down