Status
These pages describe fileshare v0.29.1.
What each release added
| v0.7.0 | a restricted share over NFS, with a kerberos block |
| v0.8.0 | the admin API over gRPC; directory shares; /healthz, /readyz, /metrics |
| v0.9.0 | TLS for WebDAV, S3 and NFS, from files or ACME; WebDAV with passwords refused in the clear |
| v0.10.0 | reading the directory again: reload = "5m", SIGHUP, ReloadDirectory |
| v0.11.0 | SFTP for people the identity provider vouches for: its SSH CA, and opkssh |
| v0.12.0 | revocation: a KRL for the provider’s SSH certificates, a CRL for NFS identities from certificates |
| v0.13.0 | shared signals: a CAEP session-revoked voids everything the provider issued before, on every protocol |
| v0.14.0 | the security review’s fixes: share names a protocol can carry, no share containing the configuration or its secrets, source_roots checked again at start, SSF max_age ≥ 1m and retain ≥ 169h |
| v0.15.0 | a KRL from ssh_krl_url must be signed and dated |
| v0.16.0 | revocation lists never go backwards, across a restart with ssh_krl_state_file / crl_state_file; trust anchors and list files may not lie inside a share |
| v0.16.1 | requires Go 1.26.6: nine reachable standard-library advisories in 1.26.4 |
| v0.16.2 | an NFS CRL’s signature is checked before it is parsed |
| v0.16.3 | nobody is named by an unverified email |
| v0.16.4 | tests only |
| v0.16.5 | tests only (#36: a test read a transport error as success) |
| v0.16.6 | the NFS refusal names both ways out: a kerberos block, or identity = "certificate" |
| v0.16.7 | go-authn/oidc v0.2.2: an RSA key’s size is counted in bits. Before, a 1024-bit key padded with zero octets verified a WebDAV token or an opkssh PK Token |
| v0.17.0 | a security audit’s fixes: one share may not hold another; access files (authorized_keys_file, dsn_file, …) may not lie in a share; WebDAV never turns anonymous because a directory read came back empty; S3 honours protocols; a connection that has not authenticated within 30 s is closed; an opkssh session ends at opkssh_max_age; a revoked session stays revoked and is closed |
| v0.17.1 | go-authn/oidc v0.2.4 (no key set behind a redirect to http), servercert v0.3.0 (the ACME cache path checked like sshd’s StrictModes), krl v0.5.0, revocation v0.3.0 |
| v0.17.2 | go-filesystems/s3 v0.3.0: S3 no longer tells an unauthenticated caller which access keys exist; presigned URLs work, last a week at most, and are refused before their own date |
| v0.18.0 | CI pins Go 1.27.1 instead of stable |
| v0.18.1 | fileshare check warns when an oidc block has no domains: a provider’s bare name reaches the local account of that name |
| v0.19.0 | go-authn/directory v0.11.0: a users "ldap" block refuses a cleartext bind to another machine; passwords are compared as digests, in constant time |
| v0.20.0 | local_names: the provider’s names are local names only when the oidc block says so (security audit F4) |
| v0.21.0 | volumes: a privileged fileshare provisioner creates ZFS datasets, btrfs subvolumes and XFS/ext4 project-quota directories, and the admin API serves shares from them; a full directory share is one answer on every protocol; the admin socket’s allowed_uids |
| v0.21.1 | a full share says so on SMB (STATUS_DISK_FULL) and NFS (NFS3ERR_NOSPC / NFS3ERR_DQUOT) |
| v0.22.0 | ssh_domains: an SSH certificate is accepted only where its domain grant (ssh-domain-grant@core.aai.geant.org, the EuroHPC SSH CA profile) names this host, fail-closed; ssh_accept_ungranted lets in certificates with no grant |
| v0.22.1 | go-filesystems/sftp v0.5.1: a certificate pinned to an address (source-address) is accepted from that address under ssh_domains, and on the provider’s and OpenPubkey certificates; before, it was refused from every address |
| v0.22.2 | tests and documentation only: source-address is tested from ::1 and from a second IPv4 address (127.0.0.2), under ssh_domains, and on an OpenPubkey certificate; on Linux, under FILESHARE_REQUIRE_JUDGE, a missing judge fails instead of skipping |
| v0.23.0 | a btrfs volume is the size of its quota over NFS, SMB and WebDAV (go-filesystems/nfs v0.7.0, smb v0.5.0, webdav v0.3.0 report the size at each query); before, btrfs showed the whole filesystem. A server whose shares come from the admin API no longer stops at start when it serves NFS and has no share yet |
| v0.24.0 | faster reads: a WebDAV GET of a directory or volume share goes out with sendfile(2) over plain HTTP (not over TLS), NFS reads and writes in 1 MiB (rtmax/wtmax), and SMB clients read more than 64 KiB per request (CAP_LARGE_MTU). On the CI runner, a 256 MiB file: WebDAV 6.6 GB/s, SMB 0.84, NFS 1.47 (one client) |
| v0.24.1 | security: an idle NFS connection no longer keeps the 3 MiB its largest call needed (24 idle connections held 59 MiB); an SMB frame header no longer makes the server allocate the 8 MiB it announces before the bytes arrive; an SMB request can no longer pay one credit for 4 GiB (go-filesystems/nfs v0.8.1, smb v0.6.1 and v0.6.2) |
| v0.25.0 | SFTP answers limits@openssh.com, so OpenSSH’s sftp reads in up to 255 KiB (+25%); one session holds at most 1024 open handles (go-filesystems/sftp v0.6.0) |
| v0.26.0 | server-side copy on every protocol that has one: a WebDAV COPY, an SFTP copy-data (OpenSSH’s sftp cp) and an SMB COPYCHUNK (Explorer, Linux copy_file_range) are made on the server, by copy_file_range(2) between files of the host — a reflink on btrfs and XFS, measured in CI as 0 bytes used for an 8 MiB copy. Security: a WebDAV COPY and every S3 GET/HEAD no longer read the whole file into memory; S3 streams objects of any size. Correction: v0.24.0’s sendfile for WebDAV GET only happened on read-only shares — a wrapper hid it on writable ones; it happens on both since v0.26.0 |
| v0.27.0 | ACME: the certificate is asked for at start, not at the first connection — retried after 1 min, doubling up to 1 h, while the server keeps serving; a client that sends no SNI (connecting by IP address) is given the first domain’s certificate instead of a failed handshake (go-authn/servercert v0.5.0). HARICA: only an Enterprise Admin (OV) account issues without a challenge, and CAA must allow harica.gr |
| v0.28.0 | the admin API is also served over HTTPS for OIDC tokens — Connect, gRPC-Web and gRPC on one listener, one audience per server, callers named by subject or group per issuer — the first step towards the web and native UIs |
| v0.28.1 | security: built with Go 1.27.2 and golang.org/x/net v0.60.0, which fix GO-2026-6617 (an HTTP/2 HPACK race that could crash a server), GO-2026-6613, -6612, -6611, -6610 and -6603. The admin API over HTTPS speaks HTTP/2. go install now requires Go 1.27.2, and switches to it by itself |
| v0.29.1 | a reload treats a group emptied in the directory as it treats a deleted one: it grants nothing, and the reload’s notes say group @x has no members: it grants nothing (go-authn/directory v0.12.0, which tells an empty group from a missing one) |
| v0.29.0 | WebDAV: a PROPFIND of the root lists the shares (207; Depth infinity 403, writes 405), so a file manager can mount the whole server; an upload can go in pieces, each Content-Range appended where the last ended (go-filesystems/webdav v0.6.0) — what the file explorer needs |
Upgrading to v0.21.0
A full directory share answers differently. EDQUOT (a quota) and
ENOSPC are now one error, “no space left on device (the share is full)”,
on every directory share, not only volumes: an EDQUOT that was WebDAV
500 and NFS NFS3ERR_IO is now 507 and NFS3ERR_NOSPC, and SFTP’s text
is that sentence, without the path. SMB still answers access denied. See
a full share.
Upgrading to v0.20.0
The provider’s alice no longer gets the local alice’s shares. A site
whose provider’s names are its local names adds local_names = true to the
oidc block (and sets domains); the server logs that line for each name
it refuses for want of it.
Upgrading to v0.19.0
A users "ldap" block pointing at ldap:// on another machine without
start_tls = true no longer starts: use ldaps://, or StartTLS.
Upgrading to v0.17.0
A configuration with one share inside another, two shares on one source,
or an access file (authorized_keys_file, dsn_file, bind_password_file,
the ssf ca_file) inside a share no longer starts; the error names
the share and the path.
Upgrading past v0.9.0
A configuration serving WebDAV without TLS on an address other machines can
reach, with anybody to authenticate, no longer starts. Add tls = true
and a tls block, or plaintext = true behind a TLS-terminating proxy. See
TLS.
Verified
These are things a client that this project did not write was made to do, not assertions about the code.
- macOS mounts a share over SMB while
curlis writing to the same image over WebDAV, and reads back what WebDAV wrote. Bob’s WebDAV write to a share he may only read is403; a wrong password is401. - go-smb2 — a client this project did not write — drives twenty concurrent
reads through SMB while twenty run through WebDAV, under
-race, in CI. - The access rules are checked through every protocol rather than in the configuration alone: alice writes and bob does not, over SMB and over WebDAV, and NFS is not offered the share at all.
- SFTP certificates are verified against OpenSSH’s own client, which also refuses the same key once its certificate is moved aside.
- NFS identities from certificates were measured with a real Linux client
(kernel 6.17, ktls-utils 0.9) in go-filesystems/nfs’s CI — which is how
MNTin the clear andtlshd’s pitfalls were found. - The KRL’s unsigned form is a measurement: OpenSSH 9.6 and 10.3 read a signed KRL and skip the signature (go-authn/krl, against both).
- go-authn/bridge’s interop lane (#12, #17) judges fileshare v0.13.0 against the real bridge: the KRL, the CRL over NFS, WebDAV tokens revoked over shared signals, an IdP disabled by scope, and opkssh over shared signals.
Not yet
Writes over S3. PUT and DELETE answer 403. The library can write, but
a share a person may only read has to refuse at the same place SFTP does, and
that is not wired. Refusing beats a half-written object.
An OIDC token over S3. Tokens work over WebDAV and
nowhere else. The usual route for S3 is STS AssumeRoleWithWebIdentity,
which exchanges the token for temporary credentials the client then signs
with — a different mechanism from accepting a bearer token, and not
implemented.
--isolate with an admin or a metrics block. Refused: there is no one
process an API change could be applied to. See
one process per protocol.
A person per user on a shared Linux NFS client, from a certificate. A Linux
client attaches the certificate to a mount, so every user of the mount is the
person it names. That is a property of the client, and the answer there is
sec=krb5. See what it cannot promise.
S3 itself has shipped: a share is a bucket, served over the same per-user tree SFTP uses.
Measured, and stated as measured
Claims in these pages that are insurance or measurement rather than reproductions of a defect, and are written that way in the source too:
- Eight goroutines writing through an unwrapped fat32 driver under
-raceproduce no race today. The shared lock is insurance on a contract —go-filesystems/interfacepromises nothing about concurrent path-based calls — not a fix for an observed failure. - The build-tag sizes were measured, including the
13.2 MB that
hashicorp/go-plugincosts on its own, which is what decided against a plugin framework — and the 11.7 MB gRPC costs now that the admin API brings it, which is whynogrpcexists. - A group-tag certificate extension of its own was designed and measured against Go’s X.509 parser, which refused the whole certificate; the groups travel as tag URIs instead.
Created on by tannevaled
Modified on by tannevaled