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
35 changes: 27 additions & 8 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,32 @@
# Changelog

## 0.7.1 - Unreleased

- Keep lock payload, serialization, and parsing failures outside acquisition retry handling, and scope Root failure receipts to each observation so historical errors cannot replay retry authority.
- Retry Root-backed async lock handoffs with descriptor-proven, budgeted observation discard, including Windows unlink resolution failures; verify creator bytes before admission and preserve creator-token cleanup authority on failure.
- Reject native selected ZIP entry reads whose decoded size differs from the declared uncompressed size, preserving byte caps and CRC verification.
- Canonicalize Windows synchronous lock parents consistently with Root, bound lock-file open-denial and missing-snapshot retries, use captured snapshot age for staleness, and retain failed release cleanup for retry without double-decrementing references or re-closing a consumed descriptor.
- Keep create-only Root writes from opening an existing target merely to inherit its mode, while preserving boundary, alias, hardlink, and type checks.
- Clarify that invalid UTF-8 or NUL padding in fixed TAR path fields rejects with `ArchiveSecurityError("entry-path")`.
## 0.7.1 - 2026-09-01

### Highlights

- **Make lock handoffs reliable:** recover from disappearing ownership records within retry budgets, preserve callback errors, and safely retry failed synchronous release cleanup.
- **Reject corrupt native ZIP reads:** verify decoded entry length against the declared size before returning bytes, while retaining byte caps and CRC checks.
- **Preserve long destination filenames:** use independent private staging names for Root writes and copies, ZIP extraction, and synchronous JSON writes instead of lengthening the destination basename.

### File locks

- Recover Root-backed asynchronous handoffs only with exact descriptor identity and unlink evidence, including Windows resolver `EPERM`/`EBADF` failures. Recheck canonical ancestors and charge discarded observations to retry/deadline budgets without granting release or reclaim authority. ([#189](https://github.com/openclaw/fs-safe/pull/189))
- Verify reopened Root-created sidecars against the creator's exact serialized bytes and ownership token before admission. Reject replacements and unlinked descriptors, and retain the original creator receipt for failed-acquisition cleanup. ([#189](https://github.com/openclaw/fs-safe/pull/189))
- Align Windows synchronous lock-parent canonicalization with Root, including short-name expansion, and bound lock-file create/open denials and missing or changed snapshot retries. Preserve the original `EPERM` when a retry budget is exhausted. ([#189](https://github.com/openclaw/fs-safe/pull/189))
- Determine synchronous lock staleness from the captured payload timestamp or snapshot mtime, avoiding false stale decisions after unlink or replacement. ([#189](https://github.com/openclaw/fs-safe/pull/189))
- Retain failed synchronous release cleanup for safe retries without double-decrementing references, re-closing a consumed or reused descriptor, or deleting a replacement sidecar. ([#189](https://github.com/openclaw/fs-safe/pull/189))
- Propagate payload, JSON serialization, and parsing failures unchanged without retrying the failing callback. Scope Root failure evidence to each observation so historical errors cannot trigger retries in later, nested, or concurrent acquisitions. ([#190](https://github.com/openclaw/fs-safe/pull/190))

### File writes and archives

- Keep private staging names independent of destination basenames across guarded Root writes and copies, native Windows writes, ZIP extraction, and `writeJsonSync()`. Preserve public producer filenames, custom `tempPrefix`, and literal JSON parent-path and drive-relative semantics. ([#191](https://github.com/openclaw/fs-safe/pull/191))
- Avoid opening an existing target merely to inherit its mode during create-only Root writes, while preserving boundary, alias, hardlink, and type checks. ([#189](https://github.com/openclaw/fs-safe/pull/189))
- Reject native `readArchiveEntry()` ZIP payloads whose decoded length differs from the declared uncompressed size with `ArchiveFormatError("archive-header-invalid")`, matching JavaScript behavior while preserving `maxBytes` and CRC checks. ([#189](https://github.com/openclaw/fs-safe/pull/189))

### Docs and validation

- Clarify that invalid UTF-8 or nonzero bytes after NUL terminators in fixed TAR name, linkname, and USTAR prefix fields reject with `ArchiveSecurityError("entry-path")`; this documents existing behavior. ([#189](https://github.com/openclaw/fs-safe/pull/189))
- Add cross-process contention and release-retry proofs, plus focused lock-admission and ZIP-integrity coverage in JavaScript-fallback and required-native CI paths. Refresh the release checklist for eight-package trusted publishing.

## 0.7.0 - 2026-08-31

Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

97 changes: 84 additions & 13 deletions RELEASE-PREREQS.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,100 @@
# 0.5.0 release prerequisites
# Release prerequisites

Complete this checklist in npm before pushing the first `v0.5.0` tag. The release workflow uses npm trusted publishing and has no npm token fallback.
Maintainer checklist for the protected, tag-driven [release workflow](.github/workflows/release.yml). See [the contribution guide](docs/contributing.md) for development and validation details. Publishing uses npm trusted publishing, with no npm token fallback or local publication.

## Package setup

Exactly one package is published: `@openclaw/fs-safe`. It already exists, is public, and is owned by the OpenClaw npm organization.
A release publishes eight packages:

Open its npm package settings and configure this trusted publisher:
- `@openclaw/fs-safe`: JavaScript, declarations, and documentation; no embedded native binaries.
- `@openclaw/fs-safe-darwin-arm64`
- `@openclaw/fs-safe-darwin-x64`
- `@openclaw/fs-safe-linux-arm64-gnu`
- `@openclaw/fs-safe-linux-arm64-musl`
- `@openclaw/fs-safe-linux-x64-gnu`
- `@openclaw/fs-safe-linux-x64-musl`
- `@openclaw/fs-safe-win32-x64-msvc`

The `native/` npm workspace and Rust crate are private build inputs, not additional published packages. The seven native packages are platform-filtered optional dependencies of the root package.

Each published package must have this trusted publisher configured in npm:

| npm trusted-publisher field | Required value |
|---|---|
| Provider | GitHub Actions |
| Organization or user | `openclaw` |
| Repository | `fs-safe` |
| Workflow filename | `release.yml` |
| Environment | Leave empty; this workflow does not use a GitHub environment. |
| Environment | Leave empty; the workflow does not use a GitHub environment. |

Use the existing package and publisher configuration; do not bootstrap or reconfigure it merely to retry a release. Publishing maintainers must have 2FA enabled. Do not add `NPM_TOKEN` or an automation token to GitHub.

## Prepare the release candidate

Update the root package version, all seven native package versions, all seven exact root optional-dependency pins, the private native npm workspace version, and the crate version in `native/Cargo.toml`. The root `Cargo.toml` is an unversioned workspace.

Regenerate the lockfiles rather than editing them by hand:

```bash
pnpm install
```

```bash
cargo update --workspace --offline
```

Inspect both lockfile diffs for unrelated dependency changes. Use the toolchain versions declared in the repository and workflow.

Finalize a nonempty, dated `## X.Y.Z - YYYY-MM-DD` changelog section, including every user-visible change since the preceding release. Generate and inspect its release notes:

```bash
pnpm release:notes X.Y.Z
```

Run the release checks on the candidate:

```bash
pnpm check
```

```bash
pnpm test:security
```

```bash
cargo test --workspace --locked
```

```bash
cargo clippy --workspace --locked -- -D warnings
```

```bash
pnpm docs:site
```

```bash
git diff --check
```

Host-native package proof additionally uses `pnpm native:build` followed by `pnpm package:smoke`. Its synthetic foreign-platform filtering fixtures are not foreign runtime proof. Full `pnpm package:collect` requires all seven real bindings assembled by the release workflow and must run through pnpm.

Do not commit generated `dist/` files, native binaries, or release artifacts.

## Tag and publish

Merge the reviewed release preparation into `main` after its exact-head CI is green. Confirm the intended release commit is the requested latest main before creating an annotated, protected `vX.Y.Z` tag on that exact commit. Push only that tag; never move or overwrite an existing release tag.

The workflow checks tag format, annotation, protection, main ancestry, matching package/crate versions and pins, and dated changelog content. Main ancestry alone does not guarantee the tag points to latest main, and the workflow does not wait for a separate CI run; maintainers must enforce both conditions before tagging.

The automated order is source validation, seven-target native build, assembly and eight-package smoke validation, draft GitHub Release creation, platform-package publication, root-package publication, cryptographic registry verification, release-note proof generation, and draft promotion. A tag push alone is not a completed release.

If a version already exists, the publishing helper verifies it instead of republishing it. Preserve the collected manifest and tarballs when investigating a failure. Never rebuild or replace published artifacts to work around a byte, signature, or provenance mismatch.

Confirm the publishing maintainers have 2FA enabled. Do not add `NPM_TOKEN` or an automation token to GitHub. The former native loader and platform package names were never published, so there is nothing to deprecate or unpublish.
## Verify the completed release

## Release commit and tag
For the root and all seven native packages, verify the exact version, expected `latest` dist-tag, canonical registry tarball URL, integrity, publication time, registry signatures, and workflow-bound provenance. Confirm the public GitHub Release and protected annotated tag exist and point to the intended commit.

- Confirm `0.5.0` in the root package, private native build workspace, and Rust crate.
- Run `pnpm install` so `pnpm-lock.yaml` matches the stable package version.
- Change `## 0.5.0 - Unreleased` in `CHANGELOG.md` to the release date.
- Run `pnpm check`, `pnpm test:security`, `cargo test --workspace --locked`, `cargo clippy --workspace --locked -- -D warnings`, `pnpm docs:site`, and `git diff --check` on the release commit.
- Merge the release commit to `main`, then create an annotated, protected `v0.5.0` tag on that exact commit.
The Release body must match the finalized changelog and include npm version links, registry tarball links, integrity, attestation proof, and the successful Actions run. Download the workflow's collected package artifacts promptly; their retention is bounded.

The workflow validates the protected annotated tag, `main` ancestry, package and crate versions, all seven non-empty native binaries, the single tarball's bytes, install/import behavior, native loading and fallback behavior, and changelog-derived release notes before it publishes anything.
Leave the repository clean on synchronized `main`. Do not prefill another release or create the next Unreleased section as part of closeout.
2 changes: 1 addition & 1 deletion native/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "fs-safe-native"
version = "0.7.0"
version = "0.7.1"
edition = "2024"
license = "MIT"
repository = "https://github.com/openclaw/fs-safe"
Expand Down
2 changes: 1 addition & 1 deletion native/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@openclaw/fs-safe-native-build",
"version": "0.7.0",
"version": "0.7.1",
"description": "Private build workspace for the native bindings bundled by @openclaw/fs-safe.",
"private": true,
"license": "MIT",
Expand Down
16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@openclaw/fs-safe",
"version": "0.7.0",
"version": "0.7.1",
"description": "Capability-style filesystem roots for Node.js apps that handle untrusted relative paths.",
"keywords": [
"filesystem",
Expand Down Expand Up @@ -149,13 +149,13 @@
"crabbox:warmup": "crabbox warmup"
},
"optionalDependencies": {
"@openclaw/fs-safe-darwin-arm64": "0.7.0",
"@openclaw/fs-safe-darwin-x64": "0.7.0",
"@openclaw/fs-safe-linux-arm64-gnu": "0.7.0",
"@openclaw/fs-safe-linux-arm64-musl": "0.7.0",
"@openclaw/fs-safe-linux-x64-gnu": "0.7.0",
"@openclaw/fs-safe-linux-x64-musl": "0.7.0",
"@openclaw/fs-safe-win32-x64-msvc": "0.7.0",
"@openclaw/fs-safe-darwin-arm64": "0.7.1",
"@openclaw/fs-safe-darwin-x64": "0.7.1",
"@openclaw/fs-safe-linux-arm64-gnu": "0.7.1",
"@openclaw/fs-safe-linux-arm64-musl": "0.7.1",
"@openclaw/fs-safe-linux-x64-gnu": "0.7.1",
"@openclaw/fs-safe-linux-x64-musl": "0.7.1",
"@openclaw/fs-safe-win32-x64-msvc": "0.7.1",
"jszip": "^3.10.1",
"tar": "7.5.22"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/darwin-arm64/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@openclaw/fs-safe-darwin-arm64",
"version": "0.7.0",
"version": "0.7.1",
"description": "macOS arm64 native binding for @openclaw/fs-safe.",
"license": "MIT",
"author": "OpenClaw Team <dev@openclaw.ai>",
Expand Down
2 changes: 1 addition & 1 deletion packages/darwin-x64/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@openclaw/fs-safe-darwin-x64",
"version": "0.7.0",
"version": "0.7.1",
"description": "macOS x64 native binding for @openclaw/fs-safe.",
"license": "MIT",
"author": "OpenClaw Team <dev@openclaw.ai>",
Expand Down
2 changes: 1 addition & 1 deletion packages/linux-arm64-gnu/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@openclaw/fs-safe-linux-arm64-gnu",
"version": "0.7.0",
"version": "0.7.1",
"description": "Linux arm64 glibc native binding for @openclaw/fs-safe.",
"license": "MIT",
"author": "OpenClaw Team <dev@openclaw.ai>",
Expand Down
2 changes: 1 addition & 1 deletion packages/linux-arm64-musl/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@openclaw/fs-safe-linux-arm64-musl",
"version": "0.7.0",
"version": "0.7.1",
"description": "Linux arm64 musl native binding for @openclaw/fs-safe.",
"license": "MIT",
"author": "OpenClaw Team <dev@openclaw.ai>",
Expand Down
2 changes: 1 addition & 1 deletion packages/linux-x64-gnu/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@openclaw/fs-safe-linux-x64-gnu",
"version": "0.7.0",
"version": "0.7.1",
"description": "Linux x64 glibc native binding for @openclaw/fs-safe.",
"license": "MIT",
"author": "OpenClaw Team <dev@openclaw.ai>",
Expand Down
2 changes: 1 addition & 1 deletion packages/linux-x64-musl/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@openclaw/fs-safe-linux-x64-musl",
"version": "0.7.0",
"version": "0.7.1",
"description": "Linux x64 musl native binding for @openclaw/fs-safe.",
"license": "MIT",
"author": "OpenClaw Team <dev@openclaw.ai>",
Expand Down
2 changes: 1 addition & 1 deletion packages/win32-x64-msvc/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@openclaw/fs-safe-win32-x64-msvc",
"version": "0.7.0",
"version": "0.7.1",
"description": "Windows x64 MSVC native binding for @openclaw/fs-safe.",
"license": "MIT",
"author": "OpenClaw Team <dev@openclaw.ai>",
Expand Down
14 changes: 7 additions & 7 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.