8000 feat(smb): share the graph's file tree read-only over SMB by adeelahmad · Pull Request #305 · adeelahmad/lense · GitHub
[go: up one dir, main page]

Skip to content

feat(smb): share the graph's file tree read-only over SMB - #305

Merged
adeelahmad merged 7 commits into
mainfrom
claude/project-thread-ctpu0l
Oct 11, 2026
Merged

adeelahmad merged 7 commits into
mainfrom
claude/project-thread-ctpu0l

Conversation

@adeelahmad
@adeelahmad adeelahmad commented Oct 10, 2026 •
Copy link
Copy Markdown
Owner

Requested by Adeel · project thread

Builds on #290 (the file tree) and #324 (S3 access keys: s3.lookup_key, s3.touch), both merged. Checked locally against s3.py: a real key signs in, its owner's view is listed and read, last_used_at is updated, and revoking the key ends the session.

Description

Before: the file tree could be browsed through the API, MCP, S3 and WebDAV, but not mounted as an SMB network drive.

After: Settings → SMB share → Share the file tree over SMB serves it read-only to Finder (smb://<host>:1445/LENS), Linux (mount -t cifs, or a file manager) and Windows (installed with LENS_SMB_PORT=445, because Explorer only uses 445). People sign in with a file access key (the same keys as S3): the key id is the user name and the secret is the password. Each person sees what the web app shows them. It's off by default, and the SMB server (impacket) is fetched only when the share is turned on.

How: the worker runs impacket's SMB server (pure Python, modified Apache 1.1 license), installed as the smb extra by the components keeper. impacket serves folders through os; here its module-level os is a read-only stand-in (domain/smb_share.py, VirtualOS) that answers from filetree.Tree for the signed-in key's owner and streams files as they're read. The server is hardened for this use:

  • a random NTLM challenge per connection;
  • no guest or anonymous sessions;
  • SMB1 refused after negotiation;
  • impacket's NTLM-response logging silenced;
  • connections only from smb.allowed_networks;
  • revoked keys and disabled accounts cut off within 30 s;
  • turning the share off ends open sessions.

Status is at GET /api/v1/settings/smb/status. The worker container publishes the share on host port 1445 at LENS_SHARE_BIND/LENS_BIND, beside the S3 and WebDAV ports; install.sh keeps a LENS_SMB_PORT given on the install line.

Motivation and Context

Adeel asked for the graph as a folder and file tree over S3, SMB and NFS, with a separate thread for each. This PR covers SMB. Samba is GPL and would need a FUSE mount, so it uses impacket, which is permissive and runs in-process.

Steps to reproduce (if appropriate):

tests/domain/test_smb_share.py signs in with impacket's own SMB client. It covers per-person views on the real file tree, read-only enforcement, wrong passwords, guests, revoked keys, allowed networks, and the worker following the settings. I also checked by hand with Samba's smbclient (max protocol SMB2 and SMB3): it lists the share, reads a 1 MB file byte-for-byte, and shows the share in -L. put, mkdir and delete are denied, an SMB1-only client is cut off, and an anonymous client is denied.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change; ! in the title)

Checklist:

  • The title is a Conventional Commit.
  • My code follows the code style of this project (make hooks checks it on commit).
  • I added or updated tests.
  • My change requires documentation updates, and I have updated docs/ accordingly (docs/smb.md, docs/file-tree.md).
  • Users need more than the title to understand it, so I wrote it under ## Unreleased in CHANGELOG.md.

Done questions

  1. Goal delivered and merged green: merged on green CI.
  2. Agents can use it: yes. Status is at GET /settings/smb/status, it's turned on and off with PUT /settings/smb, and the tree itself is in MCP.
  3. Zero setup after the install line: yes. It's off by default, and turning it on fetches impacket automatically.
  4. Fewest clicks: yes. One switch, and Settings shows the address once it's running.
  5. Every setting in the web app with a default: enabled and allowed_networks are. The host port is set on the install line because Docker publishes ports when containers are created (like LENS_S3_PORT).
  6. Light on a Pi: yes. Nothing is installed or listening until it's turned on, and it's pure Python.
  7. Private and secure: read-only, per-person keys and views, allowed networks only, and the threat model is updated (P-SMB). SMB 2.0 has no encryption on the wire, which is documented.
  8. Cheapest path: n/a, no model calls.
  9. Defaults unchanged: yes, it's off.
  10. Safe upgrades: yes. It adds only the share_service status table and no stored-data change.
  11. Honest and labelled: the docs say it's built and read-only, and list what to refine later.
  12. Tested, documented, generated via tooling: yes (make openapi, uv lock). Backend suite passed locally (950), frontend settings tests and tsc too.
  13. Open standards and MIT-compatible deps: SMB2. impacket is modified Apache 1.1. Its ldap3 dependency is LGPL and only comes in with the opt-in extra.
  14. Refine later (docs/smb.md): SMB 3 encryption, Bonjour discovery, NAS packaging, and write/import.

🤖 Generated with Claude Code

https://claude.ai/code/session_01VkWr32dEQW7JiHkWwaAwSu

@adeelahmad adeelahmad self-assigned this Oct 10, 2026
@adeelahmad
adeelahmad force-pushed the claude/project-thread-ctpu0l branch from cd5567a to 83c76bf Compare October 10, 2026 22:05
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VkWr32dEQW7JiHkWwaAwSu
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VkWr32dEQW7JiHkWwaAwSu
@adeelahmad
adeelahmad marked this pull request as ready for review October 11, 2026 00:59
@adeelahmad
adeelahmad merged commit ce486eb into main Oct 11, 2026
19 checks passed
@adeelahmad
adeelahmad deleted the claude/project-thread-ctpu0l branch October 11, 2026 01:05
adeelahmad added a commit that referenced this pull request Oct 11, 2026
…monitoring switch as built (#351)

"Ask" names the built-in Telegram bot (#293) and Slack app (#287); "Connect your agents" adds mounting the graph's
files read-only over S3, WebDAV, NFS or SMB (#324, #295, #305) and copying the MCP address from the account menu
(#340); "Watch it run" says one switch in the web app starts Prometheus and Grafana (#337); "Light by default" adds
the cloud model presets (#334). The docs index gains the NFS and SMB pages, and "In progress" keeps only open PRs.


Claude-Session: https://claude.ai/code/session_01HDx7PPUauyjMn1LZs8JAsS

Co-authored-by: Adeel Ahmad <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

0