Skip to content

ObjectFS v0.10.2

Choose a tag to compare

@github-actions github-actions released this 02 Aug 21:34
· 152 commits to main since this release
1a815a9

A packaging release, cut for one reason: v0.10.1 was tagged two hours before the module-path fix
merged, so the published tag still declared module github.com/objectfs/objectfs and
go get github.com/scttfrdmn/objectfs@v0.10.1 failed with module declares its path as — the exact
defect #213 was filed for. The fix existed on main and in no tag, which from a user's position is
indistinguishable from not being fixed. Everything else here is the packaging and contributor-path
work that landed alongside it.

Added

  • SECURITY.md — a security policy, with private vulnerability reporting enabled on the repository so a finding has somewhere to go that is not the public issue tracker. It documents what a reader cannot get from the code quickly: that the trust boundary is the mounting host and ObjectFS enforces no authorization of its own, that two unauthenticated HTTP listeners bind all interfaces by default (:8080 metrics and debug endpoints, :8081 health) with the switch that turns each off, that mode: off is the encryption default and what changed after the withdrawn v0.10.0 at_rest key, and both stated limits of the SHA-256 read verification — a partial read is not verified, and an object with no recorded checksum verifies trivially. Every claim in it was verified by execution rather than read off the configuration schema, which is how the two listener defects below were found

Fixed

  • The test harness could record a request after the client already had the response, so its own assertions were load-dependent. internal/testaws proxies every request and logs it, and the read-path suite asserts on that log: bytes transferred and GETs issued are how read amplification and cache behaviour are measured, because neither the AWS SDK nor the emulator reports them. The log entry was appended after proxy.ServeHTTP returned — but the proxy writes the body to the socket inside that call, so a client could hold every byte of a response whose request was not yet recorded. Measured at 45–70 of 640 concurrent ranged reads. The visible symptom was in a different package: internal/fuse TestShortFileIsServedFromCache failed on its precondition — "the first read issued no GET" — which reads as the read path serving bytes from a cache the fixture had just created empty, in a test whose entire subject is cache correctness. One CI run in seven. Requests are now published on arrival and their response fields filled in on completion, with the accessors waiting for anything still in flight; verified in both directions, since a regression test that cannot fail proves nothing
  • The module could not be imported under the name it gave for itself. go.mod declared module github.com/objectfs/objectfs, and the code lives at github.com/scttfrdmn/objectfs. Go resolves an import path by fetching that path, so go get github.com/scttfrdmn/objectfs failed on the mismatch between the path requested and the path declared, while the declared path is a different project — an unrelated Python repository from 2017, 28 stars, last pushed 2019, in a single-repo organisation created the same day. Nothing published has ever existed at the declared path, which is why pkg.go.dev had nothing to index and the Go Reference badge rendered empty. The path is corrected in go.mod and in all 154 files that named it — 132 Go files, plus the goimports local-prefixes setting in .golangci.yml, the Dockerfile image-source label, and the repository URLs in the Python and JavaScript SDK manifests, which pointed contributors at the wrong project. Verified by building an external consumer module against the corrected path, rather than by grepping for the string. This is breaking for any code that imported the old path, though nothing could have: it was never fetchable
  • Dependabot could not update Go dependencies, and had never merged anything. Two unrelated defects presenting as one symptom. The Go ecosystem failed on twelve consecutive weekly runs while docker succeeded in the same runs — Dependabot aborts per-ecosystem, so one broken ecosystem is silent unless the run list is read. The cause was upstream and is now resolved: proxy.golang.org had no .mod for the pinned cargoship version, Go fell through to direct git, and git reported the proxy's 404 as could not read Username for 'https://github.com' — an authentication message for what was not an authentication failure, which is what sent the previous diagnosis after a credential that was never missing. Separately and more consequentially, .github/dependabot.yml labelled every PR automerge and that label did not exist; Dependabot drops unknown labels without reporting it, and every approve and merge step in dependabot-automerge.yml was gated on it, so 46 PRs were opened and none were ever merged. The label is now declared in .github/labels.yml alongside the four others the config names
  • .github/dependabot.yml: maven and npm ecosystems for sdks/java, docs-platform, and sdks/javascript. Eight open Dependabot alerts — five against jackson-databind, three against vite, three of the eight high severity — were against manifests no ecosystem entry covered, so nothing could act on them. sdks/javascript is included because CI runs npm install && npm test there on every PR, which makes its dependencies executed code. A ceiling worth stating: the npm security updates still cannot apply, because neither directory commits a lockfile and Dependabot cannot determine the installed version without one (#214)
  • .github/workflows/dependabot-automerge.yml waited on check-regexp: (test|lint|security).*, which is case-sensitive and start-anchored, so it matched 2 of the 9 checks CI produces and ignored coverage, config-examples, every cross-build matrix leg, sdk-metrics, fuzz-smoke, and Security Scan. The wait step is removed rather than corrected: which checks must pass now lives in branch protection on main, which also governs human PRs and cannot drift from a regexp in a workflow file. Native auto-merge is enabled on the repository, without which the --auto flag would have failed even once the label matched
  • docs-platform/docker-compose.yml was not valid YAML. Two healthcheck entries put a bare URL inside a flow sequence, where the scanner reads http as a plain scalar and then meets : in place of , or ]. Docker's own parser is lenient enough to accept it, so it went unnoticed — but pre-commit run check-yaml --all-files failed on the file, which is the first thing a new contributor runs
  • .gitignore did not cover coverage/, the directory make coverage writes into. The three bare coverage.* filenames only match a profile written to the repository root, which no target produces
  • scripts/setup-hooks.sh — the first command CONTRIBUTING.md tells a contributor to run — failed on any current macOS or Debian host, and exited 0 having installed nothing. Five defects: pip3 install pre-commit ran first and dies with externally-managed-environment on a Homebrew or Debian Python (PEP 668), and because the installer was an if/elif chain testing only whether each command exists, a failing pip3 never fell through to the brew branch that would have worked; the failure happened inside a condition, so set -euo pipefail did not catch it; it installed gosec from github.com/securecodewarrior/gosec, which is a 404 (the real module is securego/gosec, which security.yml already uses); it pinned golangci-lint v1.55.2 against a version: "2" config only v2.x can parse, handing contributors a lint failure that looks like their fault; and it wrote a .golangci.yml if none was present, containing linters removed from golangci-lint years ago — now that a real config is committed, that branch would have overwritten it with an unusable one. Each install method is now tried until one succeeds, pipx first, every path verifies the command is on PATH afterwards, and the golangci-lint check is version-aware rather than presence-only. It also no longer overwrites .git/hooks/pre-commit with a hand-rolled wrapper that blocked any commit touching a line matching fmt.Print or TODO, including inside a string literal or a comment explaining why a TODO is deliberate
  • make printed four overriding commands for target warnings on every invocation, including make help. BUILD_DIR := build and COVERAGE_DIR := coverage made the directory-creation rule read bin build dist coverage:, colliding with the real build and coverage targets. The build worked — the later recipe wins, and both are .PHONY — but a build system that opens with four warnings reads as unmaintained, and the names would have genuinely collided the moment one stopped being .PHONY. Replaced with a %/.mkdir sentinel rule, which keeps the pattern out of the target namespace, declared as an order-only prerequisite so writing one binary does not rebuild its siblings
  • pre-commit run --all-files could not complete: the pretty-format-yaml hook crashed on import, because the pinned rev imports pkg_resources, which modern setuptools no longer ships (Python 3.14 here). Bumped to a rev that does not. Fixing it exposed a second problem worth recording, since the obvious repair is the wrong one: check-yaml is PyYAML and follows YAML 1.1, where a bare URL in a flow sequence is a syntax error, while pretty-format-yaml is ruamel and follows YAML 1.2, where it is legal — so quoting the URL to satisfy the first makes the second strip the quotes straight back off, and the two hooks disagree forever. The docker-compose.yml healthchecks are now block sequences, the one form both parsers accept and where there are no quotes left to remove
  • .golangci.yml is excluded from the pretty-format-yaml hook, which damages it: the formatter dedents every block sequence to its parent's column, destroying the nesting that makes linters.settings.<name> readable and pushing each trailing comment out of alignment with the entry it annotates — and those comments are the recorded reason each linter is on or off. It also unquotes the path:/text: regexes, leaving fuzz_.*_test\.go bare where the escapes were visibly protected. Both forms are valid YAML and golangci-lint parses either; the file is configuration a human has to read, and the formatter optimises for neither
  • .markdownlint.yaml: MD010 (no-hard-tabs) now exempts code blocks. The hook runs markdownlint --fix, and at the rule's default the fixer silently rewrites tabs inside fenced blocks to spaces — so every Go sample in the repository was being converted to something gofmt would immediately change back. It had already done this to the s3.NewBackend example in README.md, on a commit that only touched badges. Tabs in prose are still flagged, which is the part of the rule worth having
  • The security issue template pointed at "Security → Advisories → New draft advisory" as prose rather than a link, on a repository where private reporting was not enabled — so the instruction was both unfollowable and, until now, describing a feature that was off. It now links directly to the advisory form and to SECURITY.md

Removed

  • README_CROSS_PLATFORM.md and RELEASE_NOTES_v0.1.0.md. The first documented installing and running an objectfs-windows.exe and stated the filesystem "works on Windows/macOS/Linux"; Windows is unsupported, there is no Windows binding, and make build-all deliberately builds linux and darwin only. Nothing linked to either file
  • Three README badges that reported nothing. codecov rendered "unknown" against a service nothing has ever uploaded to (coverage is gated per-package by scripts/coverage-gate.sh in CI, which the CI badge already covers), Go Report Card rendered "retired", and Go Reference rendered empty because go.mod declared a module path that was not where the code lives (fixed below, #213). A badge that renders "unknown" reads as a broken project to anyone who looks at it and as a passing check to anyone who does not

Verify a download:

sha256sum -c objectfs-<platform>.tar.gz.sha256

Container image: ghcr.io/scttfrdmn/objectfs:0.10.2

Full changelog: https://github.com/scttfrdmn/objectfs/blob/v0.10.2/CHANGELOG.md