hacdias/webdav
A simple and standalone WebDAV server.
Healthy across the board
weakest axisPermissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 2d ago
- ✓9 active contributors
- ✓MIT licensed
Show all 6 evidence items →Show less
- ✓CI configured
- ✓Tests present
- ⚠Concentrated ownership — top contributor handles 51% of recent commits
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/hacdias/webdav)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/hacdias/webdav on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: hacdias/webdav
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/hacdias/webdav shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across the board
- Last commit 2d ago
- 9 active contributors
- MIT licensed
- CI configured
- Tests present
- ⚠ Concentrated ownership — top contributor handles 51% of recent commits
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live hacdias/webdav
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/hacdias/webdav.
What it runs against: a local clone of hacdias/webdav — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in hacdias/webdav | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 32 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of hacdias/webdav. If you don't
# have one yet, run these first:
#
# git clone https://github.com/hacdias/webdav.git
# cd webdav
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of hacdias/webdav and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "hacdias/webdav(\\.git)?\\b" \\
&& ok "origin remote is hacdias/webdav" \\
|| miss "origin remote is not hacdias/webdav (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 4. Critical files exist
test -f "main.go" \\
&& ok "main.go" \\
|| miss "missing critical file: main.go"
test -f "lib/handler.go" \\
&& ok "lib/handler.go" \\
|| miss "missing critical file: lib/handler.go"
test -f "lib/config.go" \\
&& ok "lib/config.go" \\
|| miss "missing critical file: lib/config.go"
test -f "cmd/root.go" \\
&& ok "cmd/root.go" \\
|| miss "missing critical file: cmd/root.go"
test -f "lib/files.go" \\
&& ok "lib/files.go" \\
|| miss "missing critical file: lib/files.go"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 32 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~2d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/hacdias/webdav"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
A lightweight, standalone WebDAV server written in Go that exposes a filesystem over the WebDAV protocol, enabling remote file access and synchronization via standard clients (Windows, macOS, Linux). It handles user authentication, permission control, file locking, and TLS, with configuration via YAML/JSON/TOML and deployment ready via Docker. Simple monolithic structure: main.go is the entry point; cmd/ contains CLI logic split across cmd/root.go (command setup), cmd/cmd.go (execution), cmd/bcrypt.go (password hashing), cmd/version.go (versioning); lib/ contains the core server logic (handler.go wraps Go's webdav handler, config.go parses YAML/JSON/TOML, user.go manages auth, permissions.go enforces access, locksystem.go implements WebDAV locking, files.go handles filesystem operations). Dockerfile enables containerization; compose.yml provides example orchestration.
👥Who it's for
System administrators and DevOps engineers who need to quickly deploy a WebDAV-based file sharing service without managing full-featured NAS appliances; developers integrating WebDAV into Go applications via the library; container operators looking for a minimal, self-contained alternative to Nextcloud or Apache WebDAV.
🌱Maturity & risk
Production-ready and actively maintained. The project uses semantic versioning (v5 visible in go.mod), includes comprehensive CI/CD pipelines (build.yml, docker.yml, test.yml, releaser.yml), has test coverage (handler_test.go, config_test.go), and targets Go 1.25.0. Docker Hub shows active pull counts, indicating real-world usage.
Low risk for a single-maintainer project (hacdias). Dependencies are minimal and well-maintained (go-viper for config, spf13/cobra for CLI, uber/zap for logging, studio-b12/gowebdav for WebDAV). The small Go codebase (~45KB) reduces surface area. However, no obvious security audit history is visible; WebDAV itself has known security pitfalls (lock bypasses, race conditions) that require careful server implementation.
Active areas of work
No specific PR/issue data visible in provided file list, but the repository structure suggests active maintenance: CI workflows are comprehensive (GitHub Actions for build, lint, test, docker, release), Renovate auto-updates dependencies (renovate.json present), and goreleaser.yml is configured for multi-platform binary distribution. The recent Go version target (1.25.0) indicates ongoing modernization.
🚀Get running
Check README for instructions.
Daily commands:
Development: go run main.go -c config.yml (assumes config.yml in current dir with address/port/data settings). Production: go build && ./webdav -c /path/to/config.yml. Docker: docker-compose up (uses compose.yml). The server listens on configurable address:port (default 0.0.0.0:6065) and serves WebDAV at the configured prefix (default '/').
🗺️Map of the codebase
main.go— Entry point that initializes the WebDAV server; every contributor must understand how the application starts.lib/handler.go— Core HTTP handler implementing WebDAV protocol operations; essential for understanding request routing and file operations.lib/config.go— Configuration management using Viper; critical for understanding how settings are loaded and applied across the server.cmd/root.go— CLI root command using Cobra; entry point for command-line argument parsing and application initialization.lib/files.go— File system abstraction layer handling WebDAV file operations; core business logic for all file interactions.lib/permissions.go— Permission and authentication logic; critical for security and access control implementation.lib/locksystem.go— WebDAV lock management system; essential for understanding concurrent file access handling.
🛠️How to make changes
Add a new WebDAV protocol operation
- Identify the HTTP method (GET, PUT, PROPFIND, MKCOL, DELETE, LOCK, UNLOCK) you need to implement (
lib/handler.go) - Add a new method handler function following the pattern: func (h *Handler) handle<Method>(w http.ResponseWriter, r *http.Request) (
lib/handler.go) - Register the method in the main router section and call your handler based on r.Method (
lib/handler.go) - Use lib/files.go functions to perform actual file system operations (Create, Read, Delete, Stat, etc.) (
lib/files.go) - Check permissions via lib/permissions.go before executing the operation (
lib/permissions.go) - Write WebDAV-compliant response headers and status codes (
lib/request.go) - Add tests in lib/handler_test.go covering normal and edge cases (
lib/handler_test.go)
Add a new configuration option
- Define the config field in the Config struct with mapstructure tags (
lib/config.go) - Add the default value in the DefaultConfig function (
lib/config.go) - Update the CLI flags in cmd/root.go to accept the new option (
cmd/root.go) - Bind the CLI flag to Viper in the root command's setup (
cmd/root.go) - Use the config value in lib/handler.go or other components (
lib/handler.go) - Add tests in lib/config_test.go for loading and validation (
lib/config_test.go)
Add a new authentication/permission rule
- Define the User role and permissions in lib/user.go if needed (
lib/user.go) - Add the permission check logic in lib/permissions.go with functions like CanRead(), CanWrite(), CanDelete() (
lib/permissions.go) - Call the permission check before executing the operation in lib/handler.go (
lib/handler.go) - Return 403 Forbidden if permission denied, or 401 Unauthorized if authentication required (
lib/request.go) - Add test cases in lib/handler_test.go verifying permission enforcement (
lib/handler_test.go)
🔧Why these technologies
- Go + net/http — Lightweight, fast, single binary deployment with built-in HTTP/2 support; ideal for a standalone WebDAV server
- Spf13/Cobra — Battle-tested CLI framework for managing complex flags and subcommands; simplifies argument parsing and help generation
- Spf13/Viper — Unified configuration from multiple sources (files, env vars, flags); essential for flexible deployment scenarios
- studio-b12/gowebdav — Provides WebDAV protocol primitives and helpers; reduces custom protocol implementation burden
- Uber/zap — Structured, high-performance logging; critical for production debugging and monitoring
- golang.org/x/crypto — Secure password hashing and cryptographic operations; required for user authentication
⚖️Trade-offs already made
-
In-memory lock system (locksystem.go) rather than persistent distributed locks
- Why: Simplifies deployment and eliminates external dependencies for a standalone server
- Consequence: Lost on server restart; cannot scale across multiple instances; acceptable for single-instance WebDAV use
-
File system abstraction (files.go) with direct OS file operations
- Why: Direct control, no ORM/database overhead, leverage OS caching for performance
- Consequence: Not suitable for cloud object storage; permissions tied to OS user model; requires careful symlink/escape handling
-
Configuration via YAML/TOML files + CLI flags, no hot-reload
- Why: Simplicity and predictability; server restart ensures clean state
- Consequence: Downtime required for configuration changes; cannot be used in auto-scaling environments without custom scripts
-
Single-threaded request handling (standard Go http.Server multiplexing)
- Why: Go runtime handles concurrency via goroutines; simplifies code without explicit thread management
- Consequence: Lock contention possible under high concurrent access; GC pauses could impact latency-sensitive operations
🚫Non-goals (don't propose these)
- Does not provide built-in user database or directory service integration (relies on config file or basic auth)
- Does not support distributed/clustered deployments (single-instance server only)
- Does not provide a web UI for file management (command-line and WebDAV protocol only)
- Does not handle S3 or cloud object storage backends (local file system only)
- Does not support real-time collaboration or conflict-free merging (standard WebDAV semantics only)
🪤Traps & gotchas
- Configuration file path must be passed with -c flag; if absent, server will fail without clear error. 2. User passwords in config must be bcrypt hashes (use
webdav bcrypt <password>CLI command, not plaintext). 3. File permissions in config (create/modify/delete/read per-user) are not filesystem-level; the server enforces them in-process, so direct filesystem access bypasses them. 4. TLS cert/key paths are relative to working directory if not absolute; Docker users must volume-mount or use absolute paths. 5. The embedded net/http/webdav.Handler expects a FileSystem interface; custom filesystems can be passed via lib/files.go but its implementation is not visible in the file list—check if it exists or relies on os.Open.
🏗️Architecture
💡Concepts to learn
- WebDAV (Web Distributed Authoring and Versioning) — This project is a WebDAV server implementation; understanding HTTP extensions like PROPFIND (list files), MKCOL (create folders), LOCK/UNLOCK (concurrency control), and MOVE (atomic renames) is essential to debug client compatibility and implement new features.
- HTTP Basic Authentication — hacdias/webdav uses HTTP Basic Auth (username:password Base64-encoded in Authorization header) with bcrypt hashing; understanding its limitations (cleartext over HTTP unless TLS is enabled) and Go's net/http auth middleware patterns is needed to modify user.go and handler.go.
- File Locking (WebDAV LOCK mechanism) — WebDAV's LOCK/UNLOCK operations (implemented in lib/locksystem.go) prevent race conditions when multiple clients edit the same file; understanding lock tokens, exclusive vs. shared locks, and timeout management is critical for supporting Office/OneDrive clients.
- Bcrypt Password Hashing — The server stores user passwords as bcrypt hashes (not plaintext) via golang.org/x/crypto; config.yml requires bcrypt-hashed passwords, and the CLI provides a
webdav bcryptsubcommand (cmd/bcrypt.go) to generate them—understanding salting and work factors matters for security configuration. - Configuration Unmarshaling (Viper + Mapstructure) — hacdias/webdav uses spf13/viper to parse YAML/JSON/TOML into a Go struct, with go-viper/mapstructure for type conversion; understanding struct tags and custom unmarshalers (lib/config.go) is needed to add new config fields or support new file formats.
- Cobra CLI Framework — The CLI commands (webdav --help, webdav bcrypt, webdav version) are built with spf13/cobra; understanding command registration, flag binding, and subcommand execution (cmd/root.go, cmd/cmd.go) is needed to add new CLI commands or modify argument parsing.
- Permission-Based Access Control (not filesystem ACLs) — hacdias/webdav enforces create/modify/delete/read permissions at the application level (lib/permissions.go), not via OS filesystem ACLs; this means the server process must have full filesystem access, and permission checks happen in-process—a security model very different from traditional Unix permissions.
🔗Related repos
studio-b12/gowebdav— The upstream Go WebDAV client library that hacdias/webdav depends on; understanding its PROPFIND/MKCOL/LOCK protocol implementation helps debug interoperability issues.golang/go— Go's built-in net/http and net/http/webdav packages (stdlib) that provide the foundation for the handler; source reading needed to extend or override WebDAV behavior.nextcloud/server— Full-featured WebDAV-based file sync solution; comparison point for what features this project intentionally omits (user quotas, sharing, versioning) to stay lightweight.grafana/loki— Uses same logging stack (uber/zap); useful pattern reference if you need to extend hacdias/webdav's structured logging or integrate with log aggregation (mentioned in fail2ban section of README).apache/guacamole— Alternative WebDAV setup (less common); included for ecosystem awareness—most users will compare hacdias/webdav to Nextcloud or Apache mod_dav rather than Guacamole.
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add integration tests for WebDAV operations in lib/handler_test.go
The repo has lib/handler_test.go but lacks comprehensive integration tests covering actual WebDAV protocol operations (PROPFIND, MKCOL, MOVE, LOCK, etc.). Given that lib/handler.go is the core HTTP handler, adding integration tests would catch protocol compliance issues early and improve confidence in WebDAV method implementations.
- [ ] Review lib/handler.go to identify all WebDAV methods being handled
- [ ] Add table-driven integration tests in lib/handler_test.go for each method (PROPFIND, PUT, DELETE, MKCOL, MOVE, LOCK, UNLOCK)
- [ ] Include tests for edge cases: concurrent access, lock conflicts, permission denied scenarios
- [ ] Use httptest.NewServer to test full request/response cycles
- [ ] Run tests with 'go test ./lib' to verify no regressions
Add missing tests for lib/permissions.go covering user authorization rules
The repo has lib/permissions.go but no corresponding lib/permissions_test.go file. Permission handling is security-critical for a WebDAV server. New tests would validate authorization logic across read, write, and modify operations for different user roles.
- [ ] Create lib/permissions_test.go
- [ ] Add unit tests for permission evaluation logic (e.g., CanRead, CanWrite, CanModify if these methods exist)
- [ ] Test edge cases: root path access, nested directory permissions, permission inheritance
- [ ] Test with various user configurations from lib/user.go
- [ ] Run 'go test ./lib -cover' to ensure good coverage of permissions module
Add GitHub Actions workflow for multi-platform binary compatibility testing
The repo targets Go 1.25.0 and supports multiple platforms (evidenced by .goreleaser.yml) but the test.yml workflow likely only runs on one OS. Adding a matrix strategy to test on Linux, macOS, and Windows in CI would catch platform-specific issues (e.g., path handling, file permissions) before releases.
- [ ] Review .github/workflows/test.yml current configuration
- [ ] Add 'strategy.matrix.os' with [ubuntu-latest, macos-latest, windows-latest]
- [ ] Ensure go test ./... runs on all platforms
- [ ] Verify lib/files.go file operations work cross-platform (especially path separators in Windows)
- [ ] Commit and push to verify workflow executes on all three OS runners
🌿Good first issues
- Add integration tests in lib/handler_test.go covering LOCK/UNLOCK WebDAV operations (locksystem.go is present but no tests confirm its behavior with concurrent clients).
- Document the bcrypt CLI command in README.md and compose.yml example (currently users must run
webdav bcryptmanually to generate password hashes, but this is not explained in the provided README snippet). - Implement permission deny logging in lib/permissions.go (currently permission checks happen silently; adding zap log output would help operators debug access issues, especially for fail2ban setup mentioned in the README).
⭐Top contributors
Click to expand
Top contributors
- @renovate[bot] — 51 commits
- @hacdias — 41 commits
- @networkException — 2 commits
- @Legendary4226 — 1 commits
- @emmanuel-ferdman — 1 commits
📝Recent commits
Click to expand
Recent commits
f051809— chore(deps): update golang.org/x/crypto/x509roots/fallback digest to fd0b90d (renovate[bot])f13c884— chore(deps): update module go.uber.org/zap to v1.28.0 (renovate[bot])cef2e3b— chore(deps): update golang.org/x/crypto/x509roots/fallback digest to b9e5359 (renovate[bot])4fe4703— chore(deps): update golang.org/x/crypto/x509roots/fallback digest to a8e9237 (#321) (renovate[bot])882c220— chore(deps): update golang.org/x/crypto/x509roots/fallback digest to 03ca0dc (#317) (renovate[bot])4f4045d— chore(deps): update all non-major dependencies (#318) (renovate[bot])20606cd— chore(deps): update golang.org/x/crypto/x509roots/fallback digest to 8400f4a (#314) (renovate[bot])c9ca42d— chore(deps): update golang.org/x/crypto/x509roots/fallback digest to 81c6cb3 (#313) (renovate[bot])8217bc0— refactor: use http.Server (hacdias)98f8f93— chore(deps): update golang.org/x/crypto/x509roots/fallback digest to 982eaa6 (#311) (renovate[bot])
🔒Security observations
- High · Outdated Go Version in Dockerfile —
Dockerfile (line 1). The Dockerfile uses golang:1.26-alpine3.22 for building, but the go.mod specifies go 1.25.0. Additionally, Go 1.26 is not yet released (as of knowledge cutoff), which may indicate a future version or misconfiguration. Using pre-release or mismatched versions can introduce instability and unknown security issues. Fix: Use a stable, matching Go version. Update to a released version like golang:1.25-alpine3.22 and ensure go.mod matches the builder version. - High · Missing TLS/HTTPS Configuration —
Dockerfile (EXPOSE 6065) and overall configuration. The application exposes port 6065 without clear evidence of TLS/HTTPS enforcement in the Dockerfile or configuration structure. WebDAV credentials and file transfers are sensitive and should be encrypted in transit. Fix: Implement TLS/HTTPS support by default. Add certificate handling, enforce HTTPS, and document secure deployment practices. Consider exposing port 6443 for HTTPS instead of plaintext. - High · Insecure Cryptography Library Usage —
go.mod (golang.org/x/crypto v0.50.0). The dependency golang.org/x/crypto v0.50.0 is used for bcrypt operations (evident from cmd/bcrypt.go), but this version is quite old. The project uses crypto v0.50.0 when much newer versions are available, potentially missing security patches and improvements. Fix: Update golang.org/x/crypto to the latest stable version to benefit from security patches and improved cryptographic implementations. - Medium · Missing Security Headers Configuration —
lib/handler.go (inferred). No evidence of security headers (CORS, CSP, X-Frame-Options, etc.) being properly enforced. While github.com/rs/cors is present, there's no clear indication of comprehensive security header implementation for WebDAV responses. Fix: Implement comprehensive HTTP security headers including Content-Security-Policy, X-Content-Type-Options, X-Frame-Options, and Strict-Transport-Security. Properly configure CORS with restrictive defaults. - Medium · Authentication Mechanisms Not Clearly Documented —
lib/user.go, lib/permissions.go, and configuration documentation. The presence of cmd/bcrypt.go and lib/user.go suggests authentication is implemented, but the README and visible configuration don't clearly document authentication requirements, enforcement, or best practices for credential storage. Fix: Document authentication mechanisms clearly. Ensure passwords are properly hashed with bcrypt, salt is used, and authentication is mandatory for sensitive operations. Implement rate limiting on authentication attempts. - Medium · Insufficient Input Validation for WebDAV Operations —
lib/handler.go, lib/files.go, lib/request.go. WebDAV implementations are prone to path traversal and directory listing attacks. While lib/permissions.go exists, there's insufficient visibility into input validation for file paths, request handling, and access controls. Fix: Implement strict input validation for all WebDAV operations. Validate and sanitize file paths to prevent directory traversal attacks. Use allowlists for operations and verify all path access against permission controls. - Medium · No Visible Logging of Security Events —
lib/handler.go and overall logging configuration. While go.uber.org/zap is used for logging, there's no clear evidence of comprehensive security event logging (authentication failures, unauthorized access attempts, suspicious operations). Fix: Implement comprehensive security event logging including authentication attempts, permission denials, and unusual operations. Ensure logs are protected and monitored. - Medium · Scratch Image Lacks Security Tools —
Dockerfile (final stage). The final Docker image uses 'FROM scratch', which is minimal but provides no shell, CA certificates, or debugging tools. More importantly, without Alpine or another base image, CA certificates for HTTPS validation may be missing. Fix: Include CA certificates in the scratch image by copying from the builder stage. Consider using a minimal base image like alpine:3.22 instead of scratch if additional security tools are needed for runtime validation. - Low · Potential Information Disclosure via Version String —
undefined. undefined Fix: undefined
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.